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

 更新时间:2021年10月14日 11:47:03   作者:码上夏雨  
这篇文章主要介绍了Android Compose之伸缩ToolBar的实现,本文给大家分享主要实现思路及实现过程,通过实例代码给大家介绍的非常详细,需要的朋友可以参考下

ScrollableAppBar

效果图

  • 当列表向上移动时,会先带动ToolBar向上位移,等ToolBar向上移动到最大位移量时列表向上滑动
  • 当列表向下移动时,会先带动ToolBar向下位移,等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 = with(LocalDensity.current) { navigationIconSize.roundToPx().toFloat() }

同时需要定义从外部获取到的偏移量

val toolbarOffsetHeightPx: MutableState<Float> //向上偏移量

最外层布局位移定义

为根布局添加垂直方向上的位移

@Composable
fun ScrollableAppBar(
    modifier: Modifier = Modifier,
    title: String = stringResource(id = R.string.app_name), //默认为应用名
    navigationIcon: @Composable () -> Unit, //导航图标
    @DrawableRes backgroundImageId: Int, // 背景图片
    scrollableAppBarHeight: Dp, //定义的ScrollableAppBar高度
    toolbarOffsetHeightPx: MutableState<Float> //向上偏移量
) {
    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()

完整实现

// 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内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • Android 两种启动模式的实例详解

    Android 两种启动模式的实例详解

    这篇文章主要介绍了Android 两种启动模式的实例详解的相关资料,Activity的两种启动模式:FLAG_ACTIVITY_CLEAR_TOP和FLAG_ACTIVITY_REORDER_TO_FRONT ,需要的朋友可以参考下
    2017-08-08
  • Android 自动化测试经验分享 深入UiScrollable

    Android 自动化测试经验分享 深入UiScrollable

    UiScrollable是一个UiCollection(这东西还没搞懂),我们可以使用它,在可滑动的页面(水平滑动或上下滑动都可以)上查找我们想要的控件(item)
    2013-05-05
  • Android中监听判断网络连接状态的方法

    Android中监听判断网络连接状态的方法

    这篇文章主要介绍了Android中监听判断网络连接状态的方法,介绍了是否有网络连接判断、连接的类型和监听网络状态的方法,需要的朋友可以参考下
    2014-06-06
  • Android操作Excel文件的功能实现

    Android操作Excel文件的功能实现

    本篇文章主要介绍了Android操作Excel文件的功能实现,Android中操作Excel文件导出报表时主要采用开源库jxl,有兴趣的可以了解一下。
    2017-03-03
  • Android中ViewPager组件的基本用法及实现图片切换的示例

    Android中ViewPager组件的基本用法及实现图片切换的示例

    这篇文章主要介绍了Android中ViewPager组件的基本用法及实现图片切换的示例,ViewPager主要被用来实现滑动切换效果,需要的朋友可以参考下
    2016-03-03
  • android 左右滑动+索引图标实现方法与代码

    android 左右滑动+索引图标实现方法与代码

    使用Gallery和ImageView实现android左右滑动+索引图标效果,接下来详细介绍,有需要的朋友可以参考下
    2012-12-12
  • Android 对话框 Dialog使用实例讲解

    Android 对话框 Dialog使用实例讲解

    对话框是在当前的页面之上弹出的小窗口, 用于显示一些重要的提示信息, 提示用户的输入,确认信息,或显示某种状态.如 : 显示进度条对话框, 退出提示.接下来通过本文给大家介绍android dialog对话框知识,感兴趣的朋友一起看看吧
    2016-09-09
  • 快速了解Android Room使用细则

    快速了解Android Room使用细则

    这篇文章主要为大家介绍了快速了解Android Room使用细则,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
    2023-03-03
  • Flutter利用Canvas绘制精美表盘效果详解

    Flutter利用Canvas绘制精美表盘效果详解

    这篇文章主要介绍了如何利用Flutter中的Canvas绘制一个精美的表盘效果,文中的实现步骤讲解详细,快跟随小编一起动手尝试一下
    2022-03-03
  • 汇总Android视频录制中常见问题

    汇总Android视频录制中常见问题

    这篇文章主要汇总了Android视频录制中常见问题,帮助大家更好地解决Android视频录制中常见的问题,需要的朋友可以参考下
    2015-12-12

最新评论