《Jetpack Compose系列学习》-16 Compose底部导航栏

2,549 阅读3分钟
底部导航栏

底部导航栏很常见,基本上市面上的APP都有,如微信:

image.png

在Android View中,实现底部导航来一般用tabLayout+viewPager来实现,在Android5.0之后,Google新增了BottomNavigationView,实现底部导航栏变得简单一些,下面我们一起来学习下在Compose中怎么去实现底部导航栏。

简单使用

首先需要我们准备数据和资源图片,如底部tab中每个tab要展示的文本+icon图片:

image.png 创建一个枚举类,用来创建底tab下的每个tab项:

enum class MainTabs(val tabName: String, @DrawableRes val icon: Int) {
    ONE("One", R.drawable.ic_nav_news_normal),
    TWO("Two", R.drawable.ic_nav_tweet_normal),
    THREE("Three", R.drawable.ic_nav_discover_normal),
    FOUR("Four", R.drawable.ic_nav_my_normal)
}

参数只有两个,一个是tab显示的内容,一个是图片资源,然后定义了4个Tab资源,分别的是ONE,TWO,THREE,FOUR。下面我们再创建每个tab对应显示的页面:

@Composable
fun One() {
    BaseDefault(content = "One")
}

@Composable
fun Two() {
    BaseDefault(content = "Two")
}

@Composable
fun Three() {
    BaseDefault(content = "Three")
}

@Composable
fun Four() {
    BaseDefault(content = "Four")
}

@Composable
fun BaseDefault(content: String) {
    Row(
        modifier = Modifier.fillMaxSize(),
        horizontalArrangement = Arrangement.Center,
        verticalAlignment = Alignment.CenterVertically
    ) {
        Text(text = content, fontSize = 50.sp) // tab对应的页面要展示的内容
    }
}

我们定义了4个页面,都是用了BaseDefault,然后传入不同的值来显示。最后我们使用底部导航栏把数据展示出来:

@Composable
fun BottomNavigationTest() {
    val tabs = MainTabs.values() // tab数据
    var position by remember { mutableStateOf(MainTabs.ONE)}
    Scaffold(
        backgroundColor = Color.Yellow, // 背景色
        bottomBar = { // bottomBar
            BottomNavigation {
                tabs.forEach { tab ->
                    BottomNavigationItem(
                        modifier = Modifier.background(MaterialTheme.colors.primary),
                        icon = { Icon(painterResource(id = tab.icon), contentDescription = null) },
                        label = { Text(tab.tabName) },
                        selected = tab == position,
                        onClick = {
                            position = tab
                        },
                        alwaysShowLabel = false,
                    )
                }
            }
        }
    ) {
        when(position) { // 根据state值的变化动态切换当面显示的页面
            MainTabs.ONE -> One()
            MainTabs.TWO -> Two()
            MainTabs.THREE -> Three()
            MainTabs.FOUR -> Four()
        }
    }
}

image.png

上面代码通过枚举的values方法获取所有底tab数据,通过remember方法记住默认Tab one的state状态值,该值为MainTabs类型,完了通过我们之前学的Scaffold控件去定义整体的布局结构,我们设置了背景黄色,然后设置了bottomBar。BottomNavigation就是我们今天要学的底tab控件,通过tabs的循环遍历来添加BottomNavigationItem,每个item我们设置了对应tab的icon和文字,通过上面记住的position来确定是否选中当前的tab, 在点击onClick回调中更新postion值,最后通过when根据State值的变化动态切换当前显示的页面。

源码分析

我们一起来看看它的源码实现:

@Composable
fun BottomNavigation(
    modifier: Modifier = Modifier, // 修饰符
    backgroundColor: Color = MaterialTheme.colors.primarySurface, // 背景色
    contentColor: Color = contentColorFor(backgroundColor), // 内容颜色
    elevation: Dp = BottomNavigationDefaults.Elevation, // BottomNavigation高度
    content: @Composable RowScope.() -> Unit // 要显示的内容
) {
    // 省略...
}

参数并不多,除了修饰符,还可以设置背景色、子控件内容颜色和高度等,可以根据UI的需求设置BottomNavigation的颜色。

一个BottomNavigation中会有多个BottomNavigationItem,BottomNavigationItem用于展示实际效果。下面看看BottomNavigationItem的源码:

@Composable
fun RowScope.BottomNavigationItem(
    selected: Boolean, // 是否选中
    onClick: () -> Unit, // 点击事件
    icon: @Composable () -> Unit, // 图片资源
    modifier: Modifier = Modifier, // 修饰符
    enabled: Boolean = true, // 是否可点击
    label: @Composable (() -> Unit)? = null, // 标题文案
    alwaysShowLabel: Boolean = true, // 标题是否一直显示
    interactionSource: MutableInteractionSource = remember { MutableInteractionSource() }, // BottomNavigationItem的Interaction流
    selectedContentColor: Color = LocalContentColor.current, // 选中时文本标签和图标的颜色以及波纹的颜色
    unselectedContentColor: Color = selectedContentColor.copy(alpha = ContentAlpha.medium) // 未选中时文本标签和图标的颜色
) {
    // 省略...
}

可以看到BottomNavigationItem的参数比BottomNavigation多,但也比较简单,已添加注释。下面再看一个例子,我们把上面的示例代码稍作改动:

BottomNavigation(
    backgroundColor = MaterialTheme.colors.primary, // 背景紫色
    contentColor = Color.Red // 子控件内容红色
) {
    tabs.forEach { tab ->
        BottomNavigationItem(
            modifier = Modifier.background(MaterialTheme.colors.primary),
            icon = { Icon(painterResource(id = tab.icon), contentDescription = null) },
            label = { Text(tab.tabName) },
            selected = tab == position,
            onClick = {
                position = tab
            },
            alwaysShowLabel = true,
            selectedContentColor = Color.Green, // tab选中后颜色
            unselectedContentColor = Color.Red // tab未选中颜色
        )
    }
}

我们将BottomNavigation背景颜色设为紫色,子控件的内容颜色设为红色,将BottomNavigationItem的alwaysShowLabel设为true,还设置了选中和未选中时tab的文本标签和图标的颜色:

image.png

学完这么多Compose内容后,可以进行简单的实际项目开发了,后续会一起学习下自定义View。