前言
我们接着第一式继续往下写
正文
新闻app最起码应该有两个页面,一个列表页面,一个详情页面,列表页面我们已经完美(cu bao)地写好了,接下来我们再完美(cu bao)地写一个正文页面,并且实现导航。总结下来,接下来我们的目标有一下几个:
粗暴地完成正文页面
用compose的方式实现列表页到正文,正文到列表页之间的跳转
封装统一的actionBar(compose中叫TopAppBar)
1. 粗暴地完成正文页面
package dex.studio.compose.news.ui.pages
import androidx.compose.material.Scaffold
import androidx.compose.material.Text
import androidx.compose.material.TopAppBar
import androidx.compose.runtime.Composable
import androidx.compose.ui.text.font.FontFamily
@Composable
fun NewsDetailPage() {
Scaffold(topBar = {
TopAppBar(title = {
Text(
text = "News Detail",
fontFamily = FontFamily.Cursive
)
})
},
content = {
Text(text = "正文")
})
}
正文页面暂时写死,以后会配合网易热点新闻api做成webview的形式,主要是因为懒~~,啊tui,为了更好更直观地演示导航
2. 用compose的方式实现列表页到正文,正文到列表页之间的跳转
如果要使用声明式的Compose实现在页面中的导航,我们的大体思路就是维护一个用来导航的值,每次这个值变更后就在当前activity中显示相对应的页面。目前我们做了两个页面:1. NewsListPage.kt(列表页面)2. NewsDetailPage.kt(详情页面)。
首先声明一个枚举类,用来对应列表页和详情页:
enum class ScreenName {
ListPage, DetailPage
}
然后定义一个用来导航的值,因为这个值是用来导航的,所以必须得是在Activity中声明
private val screenName = mutableStateOf(ScreenName.ListPage)
在NewsListPage文件中,为列表页的每一项创造点击事件
Column {
Text(text = "total size == $totalSize")
LazyColumn(
modifier = Modifier
.fillMaxWidth()
.fillMaxHeight()
.background(Color.Red)
) {
items(newsList)
{ txt ->
Text(
text = txt,
fontSize = 14.sp,
fontFamily = FontFamily.Monospace,
modifier = Modifier
.clickable(
onClick = onNewsListClick//这里是点击事件
)
.background(Color.LightGray)
.fillMaxWidth()
)
}
}
}
在activity中实现这个点击事件,同时更改导航的值为详情页
NewsListPage {
screenName.value = ScreenName.DetailPage
}
当用户点击了返回按钮后,我们需要从详情页返回到列表页,所以需要在Activity中复写onBackPressed方法
override fun onBackPressed() {
if (screenName.value == ScreenName.ListPage) {
super.onBackPressed()
} else {
screenName.value = ScreenName.ListPage
}
}
到这里,我们的导航就彻底做完啦,这就是一个极简的版本,看官网给的demo是给navigation做了一个封装,这里就不详细说明了,主要是因为要突(zuo)出(zhe)重(hen)点(lan)。
3. 封装统一的actionBar(compose中叫TopAppBar)
官方说Compose使用有个好处就是可以更好地复用ui框架,所以在这里做一次尝试,封装一个顶部的bar
@Composable
fun NewsTopAppBar(title: String, isShowBack: Boolean, onClickBack: () -> Unit={}) {
TopAppBar(title = {
Text(
text = title,
fontFamily = FontFamily.Cursive,
fontSize = 24.sp,
color = Color.White
)
}, backgroundColor = ComposeNewsColor.MainColor, navigationIcon = {
if (isShowBack) {
//只有详情页才会有返回按钮
IconButton(onClick = onClickBack) {
Icon(
painter = painterResource(id = R.drawable.ic_jetnews_logo),
contentDescription = "back"
)
}
}
})
}
有几个参数,title:标题;isShowBack:是否显示返回按钮;onClickBack:对用户按下返回按钮后的监听。
敲黑板!!!不要忘记在方法上面加上注解@Composable
再敲黑板!!!用@Composable注解的方法,方法名规范写成首字母大写
这样就把TopAppBar封装好了,下面我们谈谈怎么使用
在列表页中不需要返回按钮,所以我们这样写:
Scaffold(topBar = {
NewsTopAppBar(title = "News List", isShowBack = false)
},
在详情页中需要返回按钮,所以这样写:
Scaffold(topBar = {
NewsTopAppBar(
title = "News Detail",
isShowBack = true,
onClickBack = onBackClickP
)
},
到这里我们的导航就基本完成了,目前只有两个页面,层级也只有两级,所以这么实现导航不会有太大问题,但是如果是层级很深,同时页面也多,这样写肯定不利于以后的扩展,所以有缘的话我会在后面写一个如何封装导航的文章。