前言
在上一篇文章中,我完成了登陆模块的几个首要页面,在这一篇文章中,我将运用 Jetpack Cmpose 去完成微信的主页的几个tab页首要包含微信,通讯录,发现和我。
页面构成
主页首要由一个Activity和四个组合函数页面,它们的结构如下:
页面结构梳理
咱们经过调查发现,主页是经过点击底部的导航栏或许左右滑动切换页面的,在咱们没有运用Compose开发之前,咱们是运用ViewPager + TabLayout的方法完成的,在Compose里有没有这样的组件呢?
底部导航栏的完成
在上一篇文章中,我运用了 Scaffold 脚手架,咱们看看这个脚手架的特点,有没有咱们需求的,Scaffold的特点如下:
Scaffold(
modifier: Modifier = Modifier,
topBar: @Composable () -> Unit = {},
bottomBar: @Composable () -> Unit = {},
snackbarHost: @Composable () -> Unit = {},
floatingActionButton: @Composable () -> Unit = {},
floatingActionButtonPosition: FabPosition = FabPosition.End,
containerColor: Color = MaterialTheme.colorScheme.background,
contentColor: Color = contentColorFor(containerColor),
contentWindowInsets: WindowInsets = ScaffoldDefaults.contentWindowInsets,
content: @Composable (PaddingValues) -> Unit
)
因为了解flutter开发,看了这些特点,了解的身影呈现了,没猜错的话就是bottomBar。
底部导航栏首要包含称号和图标,接下来我将封装 NavigationItem 目标来运用
/**
* 主页底部导航栏
*/
data class NavigationItem(
/**
* 称号
*/
val title: String,
/**
* 图标
*/
val icon: ImageVector,
)
这儿的图标我运用的是material自带的,经过 implementation “androidx.compose.material:material-icons-extended:$compose_version” 引入。
接下来界说导航栏的数组
val navList = listOf(
NavigationItem(
"微信",
Icons.Filled.Sms,
),
NavigationItem(
"通讯录",
Icons.Filled.Contacts,
),
NavigationItem(
"发现",
Icons.Filled.Explore,
),
NavigationItem(
"我",
Icons.Filled.Person,
),
)
底部导航栏的详细完成
bottomBar = {
NavigationBar(
modifier = Modifier.height(60.dp),
containerColor = Color(ContextCompat.getColor(context, if (selectIndex > 1) R.color.white else R.color.nav_bg)),
) {
navList.forEachIndexed { index, nav ->
Box(
contentAlignment = Alignment.Center,
modifier = Modifier
.weight(1f)
.fillMaxHeight()
) {
Column(
horizontalAlignment = Alignment.CenterHorizontally,
verticalArrangement = Arrangement.Bottom
) {
Icon(
nav.icon, null,
modifier = Modifier.size(28.dp),
tint = Color(
if (selectIndex == index) ContextCompat.getColor(context, R.color.green)
else ContextCompat.getColor(context, R.color.gray)
)
)
Text(
text = nav.title,
fontSize = 12.sp,
color = Color(
if (selectIndex == index) ContextCompat.getColor(context, R.color.green)
else ContextCompat.getColor(context, R.color.gray)
)
)
}
}
}
}
},
在这儿边,经过界说 selectIndex 来记录点击的tab,用来切换对应的样式。
看下作用
Tab页的完成
经过检查,我并没有看到 ViewPager 这样的组件,可是发现了能够完成类似功用的组件 HorizontalPager,它的结构如下:
HorizontalPager(
count: Int,
modifier: Modifier = Modifier,
state: PagerState = rememberPagerState(),
reverseLayout: Boolean = false,
itemSpacing: Dp = 0.dp,
contentPadding: PaddingValues = PaddingValues(0.dp),
verticalAlignment: Alignment.Vertical = Alignment.CenterVertically,
flingBehavior: FlingBehavior = PagerDefaults.flingBehavior(
state = state,
endContentPadding = contentPadding.calculateEndPadding(LayoutDirection.Ltr),
),
key: ((page: Int) -> Any)? = null,
userScrollEnabled: Boolean = true,
content: @Composable PagerScope.(page: Int) -> Unit,
)
这些特点没有很杂乱的,根本能够经过称号就知道它的作用了,接下来运用 HorizontalPager 来完成咱们的页面切换。
HorizontalPager(
count = 4,
state = pageState,
contentPadding = PaddingValues(horizontal = 0.dp),
modifier = Modifier.fillMaxSize()
) { page ->
when(page) {
0 -> Text(text = "这是微信页")
1 -> Text(text = "这是通讯录页")
2 -> Text(text = "这是发现页")
3 -> Text(text = "这是我页")
}
}
看下作用
仔细的肯定能够发现,页面切换时底部导航栏没有变化啊,是的,还需求将Tab页和导航栏相关起来。
只需求在点击导航栏时经过 pageState 跳转对应的页面和切换页面时监听当前的页面将咱们之前界说的 selectIndex 赋值即可,详细如下:
点击导航栏
Box(
contentAlignment = Alignment.Center,
modifier = Modifier
.weight(1f)
.fillMaxHeight()
.click {
selectIndex = index
/**
* 点击底部的tab切换对应的page
*/
scope.launch {
pageState.scrollToPage(index)
}
}
)
监听当前页面的切换
LaunchedEffect(pageState) {
snapshotFlow { pageState.currentPage }.collect { page ->
selectIndex = page
println("LaunchedEffect currentPage: $page")
}
}
看下调整后的作用
到这儿,主页的首要结构和交互已经建立完了
HomeScreen的全部完成代码如下:
@SuppressLint("UnusedMaterial3ScaffoldPaddingParameter")
@OptIn(ExperimentalMaterial3Api::class, ExperimentalPagerApi::class)
@Composable
fun HomeScreen() {
var selectIndex by rememberSaveable { mutableStateOf(0) }
val pageState = rememberPagerState(initialPage = 0)
val context = LocalContext.current
val scope = rememberCoroutineScope()
rememberSystemUiController().setStatusBarColor(Color.Transparent, darkIcons = true)
Surface(
Modifier
.fillMaxSize()
.background(MaterialTheme.colorScheme.background)
) {
Scaffold(
topBar = {
CenterAlignedTopAppBar(
title = {
Text(
titles[selectIndex],
maxLines = 1,
fontSize = 16.sp,
overflow = TextOverflow.Ellipsis
)
},
actions = {
if(selectIndex != 3) {
IconButton(
onClick = {
/* doSomething() */
}) {
Icon(
imageVector = Icons.Filled.Search,
contentDescription = null,
modifier = Modifier.size(30.dp),
tint = Color(ContextCompat.getColor(context, R.color.black_10))
)
}
IconButton(onClick = {
/* doSomething() */
}) {
Icon(
imageVector = Icons.Filled.AddCircleOutline,
contentDescription = null,
modifier = Modifier.size(25.dp),
tint = Color(ContextCompat.getColor(context, R.color.black_10))
)
}
}
},
colors = TopAppBarDefaults.mediumTopAppBarColors(
containerColor = Color(ContextCompat.getColor(context, if (selectIndex != 3) R.color.nav_bg else R.color.white)),
scrolledContainerColor = Color(ContextCompat.getColor(context, if (selectIndex != 3) R.color.nav_bg else R.color.white)),
navigationIconContentColor = Color.White,
titleContentColor = Color(ContextCompat.getColor(context, R.color.black_10)),
actionIconContentColor = Color(ContextCompat.getColor(context, R.color.black_10)),
)
)
},
bottomBar = {
NavigationBar(
modifier = Modifier.height(60.dp),
containerColor = Color(ContextCompat.getColor(context, if (selectIndex > 1) R.color.white else R.color.nav_bg)),
) {
navList.forEachIndexed { index, nav ->
Box(
contentAlignment = Alignment.Center,
modifier = Modifier
.weight(1f)
.fillMaxHeight()
.click {
selectIndex = index
/**
* 点击底部的tab切换对应的page
*/
scope.launch {
pageState.scrollToPage(index)
}
}
) {
Column(
horizontalAlignment = Alignment.CenterHorizontally,
verticalArrangement = Arrangement.Bottom
) {
Icon(
nav.icon, null,
modifier = Modifier.size(28.dp),
tint = Color(
if (selectIndex == index) ContextCompat.getColor(context, R.color.green)
else ContextCompat.getColor(context, R.color.gray)
)
)
Text(
text = nav.title,
fontSize = 12.sp,
color = Color(
if (selectIndex == index) ContextCompat.getColor(context, R.color.green)
else ContextCompat.getColor(context, R.color.gray)
)
)
}
}
}
}
},
content = { innerPadding ->
Box {
HorizontalPager(
count = 4,
state = pageState,
contentPadding = PaddingValues(horizontal = 0.dp),
modifier = Modifier.fillMaxSize()
) { page ->
when(page) {
0 -> ChatSessionScreen(innerPadding)
1 -> AddrBookScreen(innerPadding)
2 -> FindScreen(innerPadding)
3 -> MineScreen(innerPadding)
}
}
LaunchedEffect(pageState) {
snapshotFlow { pageState.currentPage }.collect { page ->
selectIndex = page
println("LaunchedEffect currentPage: $page")
}
}
}
}
)
}
}
最终,弥补下对应tab页的内容再看下作用
到这儿,运用Jetpack Compose仿微信主页UI就开发完成了,看起来是不是有模有样了。
总结
在这一期开发中,首要运用 Scaffold 脚手架的 topBar 和 bottomBar 分别完成了标题栏和底部导航栏,运用了 HorizontalPager 完成了页面切换。