Compose仿微信底部导航栏NavigationBar :底部导航控制滑动并移动

文章目录

  • 1、准备工作
  • 2、功能描述:
  • 3、实现过程
    • [3.1 创建一个数据类](#3.1 创建一个数据类)
    • [3.2 创建一个list变量](#3.2 创建一个list变量)
    • [3.3 具体实现](#3.3 具体实现)
      • [3.3.1 创建共享的Pager状态](#3.3.1 创建共享的Pager状态)
      • [3.3.2 将页面索引与页面标题同步](#3.3.2 将页面索引与页面标题同步)
      • [3.3.3 创建协程作用域](#3.3.3 创建协程作用域)
      • [3.3.4 使用HorizontalPager实现滑动效果](#3.3.4 使用HorizontalPager实现滑动效果)
      • 代码实现注意点
  • 4、关键点
    • [4.1 状态管理重构​:](#4.1 状态管理重构:)
    • [4.2 滑动与导航同步​](#4.2 滑动与导航同步)

1、准备工作

1.1 参考

组件BottomNavigation实现,版本变更后,Material 3 引入了 NavigationBar 作为 BottomNavigation 的替代品,提供更符合现代设计规范的外观和功能,使用使用 NavigationBar + NavigationBarItem进行实现。

1.2 依赖添加:

使用Bom的版本为2024.04.01,详细介绍见官网

1.3 主要控件

NavigationBar 实现在一个应用程序的主要目的地之间移动

kotlin 复制代码
@Composable
fun NavigationBar(
    modifier: Modifier = Modifier,
    containerColor: Color = NavigationBarDefaults.containerColor,
    contentColor: Color = MaterialTheme.colorScheme.contentColorFor(containerColor),
    tonalElevation: Dp = NavigationBarDefaults.Elevation,
    windowInsets: WindowInsets = NavigationBarDefaults.windowInsets,
    content: @Composable RowScope.() -> Unit
) 

HorizontalPager、VerticalPager

HorizontalPager控制控件左右移动,VerticalPager控制控件上下移动

kotlin 复制代码
@Composable
fun HorizontalPager(
    state: PagerState,
    modifier: Modifier = Modifier,
    contentPadding: PaddingValues = PaddingValues(0.dp),
    pageSize: PageSize = PageSize.Fill,
    beyondViewportPageCount: Int = PagerDefaults.BeyondViewportPageCount,
    pageSpacing: Dp = 0.dp,
    verticalAlignment: Alignment.Vertical = Alignment.CenterVertically,
    flingBehavior: TargetedFlingBehavior = PagerDefaults.flingBehavior(state = state),
    userScrollEnabled: Boolean = true,
    reverseLayout: Boolean = false,
    key: ((index: Int) -> Any)? = null,
    pageNestedScrollConnection: NestedScrollConnection = PagerDefaults.pageNestedScrollConnection(
        state,
        Orientation.Horizontal
    ),
    snapPosition: SnapPosition = SnapPosition.Start,
    pageContent: @Composable PagerScope.(page: Int) -> Unit

2、功能描述:

在底部导航栏中设置按钮,点击按钮切换页面,或者将页面左右滑动

如图所示:

3、实现过程

3.1 创建一个数据类

kotlin 复制代码
data class FileBean(
    val icon:Int = -1,
    val title:String = "",
)

3.2 创建一个list变量

bottomNavigationList 变量声明需要的icon和title内容

kotlin 复制代码
 val bottomNavigationList =
        mutableListOf(
            FileBean(
                icon = R.mipmap.icon_home_page,
                title = stringResource(R.string.home_text)
            ),
            FileBean(
                icon = R.mipmap.icon_case_page,
                title = stringResource(R.string.case_text)

            ),
            FileBean(
                icon = R.mipmap.icon_evidence_page,
                title = stringResource(R.string.evidence_text)

            ),
            FileBean(
                icon = R.mipmap.icon_request_page,
                title = stringResource(R.string.request_text)

            ),
            FileBean(
                icon = R.mipmap.icon_my_page,
                title = stringResource(R.string.my_text)
            ),
        )

3.3 具体实现

3.3.1 创建共享的Pager状态

kotlin 复制代码
val pagerState = rememberPagerState(pageCount = { bottomNavigationList.size })

3.3.2 将页面索引与页面标题同步

kotlin 复制代码
  val currentPageTitle by remember {
        derivedStateOf {
            bottomNavigationList[pagerState.currentPage].title
        }
    }

3.3.3 创建协程作用域

kotlin 复制代码
 val coroutineScope = rememberCoroutineScope()

3.3.4 使用HorizontalPager实现滑动效果

kotlin 复制代码
    val pagerState = rememberPagerState(pageCount = { bottomNavigationList.size })
    val currentPageTitle by remember {
        derivedStateOf {
            bottomNavigationList[pagerState.currentPage].title
        }
    }
    val coroutineScope = rememberCoroutineScope()
Scaffold(
        bottomBar = {
            NavigationBar(containerColor = Color.White) {
                bottomNavigationList.forEachIndexed { index, item ->
                    NavigationBarItem(
                        icon = {
                            Icon(
                                painter = painterResource(id = item.icon),
                                contentDescription = item.title
                            )
                        },
                        label = { Text(item.title) },
                        selected = currentPageTitle == item.title,
                        onClick = {
                            // 点击导航项时平滑滚动到对应页面
                            coroutineScope.launch {
                                pagerState.animateScrollToPage(index)
                            }
                        },
                        colors = NavigationBarItemDefaults.colors(
                            indicatorColor = Color.Transparent,
                            selectedIconColor = colorResource(R.color.agree_red),
                            selectedTextColor = colorResource(R.color.agree_red),
                            unselectedIconColor = colorResource(R.color.agree_grey),
                            unselectedTextColor = colorResource(R.color.agree_grey),
                        )
                    )
                }
            }
        }
    ) { paddingValues ->
        //使用HorizontalPager实现滑动效果
        HorizontalPager(
            state = pagerState,
            modifier = Modifier.padding(paddingValues),
            verticalAlignment = Alignment.Top,
            beyondViewportPageCount = 0  //正常会预加载下一页,但是页面复杂会导致性能下降,将其设置为0
        ) { pageIndex ->
            // 根据当前页面索引显示对应内容
            when (pageIndex) {
                0 -> HomePage()
                1 -> FilePage()
                2 -> VideoPage()
                3 -> RequestPage()
                4 -> MyPage()
            }
        }
    }

代码实现注意点

beyondViewportPageCount 字段

需要注意的是,使用HorizontalPager时会自动加载下一页,如果每一页面较为复杂的话,会影响性能,可以通过beyondViewportPageCount 字段控制页面的加载效果,但是会影响滑动的流畅度,可以选择进行设置。

4、关键点

4.1 状态管理重构​:

使用 rememberPagerState 统一管理页面状态

通过 derivedStateOf 自动同步页面索引和标题

4.2 滑动与导航同步​

kotlin 复制代码
// 点击导航项时滚动到对应页面
onClick = {
    coroutineScope.launch {
        pagerState.animateScrollToPage(index)
    }
}

// HorizontalPager自动更新当前页面索引
HorizontalPager(state = pagerState) { pageIndex ->
    // 显示对应页面
}
相关推荐
张风捷特烈7 分钟前
每日一题 Flutter#1 | 说说你对声明式 UI 的理解
android·flutter
移动开发者1号1 小时前
Android ContentProvider多表关联查询
android·kotlin
移动开发者1号1 小时前
显式与隐式Intent调用对比
android·kotlin
移动开发者1号1 小时前
Android后台服务保活简介
android·kotlin
移动开发者1号1 小时前
Android后台任务管理利器
android·kotlin
恋猫de小郭2 小时前
Flutter 官方多窗口体验 ,为什么 Flutter 推进那么慢,而 CMP 却支持那么快
android·前端·flutter
yan123687 小时前
Linux 驱动之设备树
android·linux·驱动开发·linux驱动
aningxiaoxixi9 小时前
android stdio 的布局属性
android
CYRUS STUDIO10 小时前
FART 自动化脱壳框架一些 bug 修复记录
android·bug·逆向·fart·脱壳