Android|Android Compose实现伸缩ToolBar的思路详解

目录

  • ScrollableAppBar
    • 效果图
    • 主要思路
      • 布局预览
      • 实现过程

ScrollableAppBar
效果图

  • 当列表向上移动时,会先带动ToolBar向上位移,等ToolBar向上移动到最大位移量时列表向上滑动
  • 当列表向下移动时,会先带动ToolBar向下位移,等ToolBar向下移动到最大位移量时列表向下滑动

主要思路

布局预览 伸缩前布局:
Android|Android Compose实现伸缩ToolBar的思路详解
文章图片

伸缩后布局:
Android|Android Compose实现伸缩ToolBar的思路详解
文章图片


实现过程 布局实现
首先我们要定义两个尺寸变量
// 应用栏高度private val toolBarHeight = 56.dp// 导航图标大小private val navigationIconSize = 50.dp

我们采用Box作为根布局,里面主要包含三个部分,背景图片,顶部的TooBar以及下面的Title部分,其实现如下
//整体布局实现Box(modifier = Modifier.height(scrollableAppBarHeight) //scrollableAppBarHeight 为高度参数,为外部获取.fillMaxWidth()) {Image(painter = painterResource(id = backgroundImageId), contentDescription = "background", contentScale = ContentScale.FillBounds)// 自定义应用栏Row(modifier = modifier.height(toolBarHeight) //设置高度为toolBarHeight.fillMaxWidth(),verticalAlignment = Alignment.CenterVertically //设置垂直方向为居中对齐) {// 导航图标Box(modifier = Modifier.size(navigationIconSize),contentAlignment = Alignment.Center) {navigationIcon()}}// title定义Box(modifier = Modifier.height(toolBarHeight) //和ToolBar同高.fillMaxWidth().align(Alignment.BottomStart),contentAlignment = Alignment.CenterStart) {Text(text = title,color = Color.White,modifier = Modifier.padding(start = 20.dp).matchParentSize(), // 使用 matchParentSize 修饰符保证不影响父 Box尺寸fontSize = 20.sp)}}

我们主要讲解title部分
// title定义Box(modifier = Modifier.height(toolBarHeight) //和ToolBar同高.fillMaxWidth().align(Alignment.BottomStart),contentAlignment = Alignment.CenterStart) {Text(text = title,color = Color.White,modifier = Modifier.padding(start = 20.dp).matchParentSize(), // 使用 matchParentSize 修饰符保证不影响父 Box尺寸fontSize = 20.sp)}

首先为了保证title部分在完全收缩后高度和toolBar部分一致,我们设置Box布局高度为toolBarHeight
modifier = Modifier.height(toolBarHeight) //和ToolBar同高.fillMaxWidth()

然后定义Box在根布局里面的对齐方式为Alignment.BottomStart
modifier = Modifier.height(toolBarHeight) //和ToolBar同高.fillMaxWidth().align(Alignment.BottomStart)

之所以这样设置,是因为我们通过观察伸缩前和伸缩后的预览图可以知道如果保证此部分是底部左边对齐,那么在根布局向上移动的过程中我们便可以只关心此部分在水平方向的位移即可
接着设置文本部分的对齐方式,保证title是居中靠左对齐的
contentAlignment = Alignment.CenterStart

位移实现
首先,我们要明确ScrollableAppBar最大向上偏移量等于其定义的高度和收缩后的高度,即toolBarHeight的差值,即:
// 应用栏最大向上偏移量val maxOffsetHeightPx = with(LocalDensity.current) { scrollableAppBarHeight.roundToPx().toFloat() - toolBarHeight.roundToPx().toFloat() }

其次,title部分在水平方向的位移距离其实就是导航图标的宽度,即:
// Title 偏移量参考值val titleOffsetWidthReferenceValue = https://www.it610.com/article/with(LocalDensity.current) { navigationIconSize.roundToPx().toFloat() }

同时需要定义从外部获取到的偏移量
val toolbarOffsetHeightPx: MutableState //向上偏移量

最外层布局位移定义
为根布局添加垂直方向上的位移
@Composablefun ScrollableAppBar(modifier: Modifier = Modifier,title: String = stringResource(id = R.string.app_name), //默认为应用名navigationIcon: @Composable () -> Unit, //导航图标@DrawableRes backgroundImageId: Int, // 背景图片scrollableAppBarHeight: Dp, //定义的ScrollableAppBar高度toolbarOffsetHeightPx: MutableState //向上偏移量) {Box(modifier = Modifier.height(scrollableAppBarHeight).offset {IntOffset(x = 0,y = toolbarOffsetHeightPx.value.roundToInt() //设置偏移量)}.fillMaxWidth()) {.... // 背景图等内容}}

toolBar垂直方向位置不变的实现
设置和父布局相反的位移量保证toolBar处于原位置,即:
// 自定义应用栏Row(modifier = modifier.offset {IntOffset(x = 0,y = -toolbarOffsetHeightPx.value.roundToInt() //保证应用栏是始终不动的)}.height(toolBarHeight).fillMaxWidth(),verticalAlignment = Alignment.CenterVertically) {... // 导航图标}

title水平位移的实现
为了保证title均匀向右位移,用根布局此时向上位移量和最大位移量的商再乘以水平方向上的总位移即可:
x = -((toolbarOffsetHeightPx.value / maxOffsetHeightPx) * titleOffsetWidthReferenceValue).roundToInt()

【Android|Android Compose实现伸缩ToolBar的思路详解】完整实现
// title部分Box(modifier = Modifier.height(toolBarHeight) //和ToolBar同高.fillMaxWidth().align(Alignment.BottomStart).offset {IntOffset(x = -((toolbarOffsetHeightPx.value / maxOffsetHeightPx) * titleOffsetWidthReferenceValue).roundToInt(), //水平方向位移y = 0)},contentAlignment = Alignment.CenterStart) {... //title部分}

项目地址
ScrollableAppBar 如果项目对你有所帮助,如果有改进意见还可以提交 issue
到此这篇关于Android Compose实现伸缩ToolBar的思路详解的文章就介绍到这了,更多相关Android 伸缩ToolBar内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

    推荐阅读