android - Jetpack Compose 中是否有类似 AppBarLayout 的 "liftOnScroll"属性的东西?

标签 android xml android-jetpack-compose

属性 app:liftOnScroll="true"在 AppBarLayout 中,当关联 View 与 app:layout_behavior="@string/appbar_scrolling_view_behavior"被滚动(通常是 RecyclerView 或带有 ScrolelView 的任何内容)。
Jetpack Compose 中有这样的东西吗?我找不到兼容的行为,TopAppBar 也没有。也不是常规的 Text (在它们的任何参数或修饰符中)。
简而言之 - 有没有办法提升类似工具栏的 View ,但只有在滚动底层列表/可滚动内容时(而不是在它的顶部)?

最佳答案

不幸的是,它还不支持。但是您可以自己创建它。您需要使用可滚动组件包装您的主要内容,并根据主要内容的滚动状态为 AppBar 的高度设置动画。
这是示例:

/**
 * AppBarScaffold displays TopAppBar above specified content. Content is wrapped with
 * scrollable Column. TopAppBar's elevation is animated depending on content scroll state.
 *
 * Back arrow is shown only if [onBackPress] is not null
 *
 * @param onBackPress Call back when back arrow icon is pressed
 */
@Composable
fun AppBarScaffold(
    modifier: Modifier = Modifier,
    title: String = "",
    onBackPress: (() -> Unit)? = null,
    actions: @Composable RowScope.() -> Unit = {},
    content: @Composable () -> Unit
) {
    val scrollState = rememberScrollState()
    val contentColor = contentColorFor(MaterialTheme.colors.background)

    val elevation by animateDpAsState(if (scrollState.value == 0) 0.dp else AppBarDefaults.TopAppBarElevation)

    Surface(
        modifier = modifier.statusBarsPadding(),
        color = MaterialTheme.colors.background,
        contentColor = contentColor
    ) {
        val topBar = @Composable { AppBar(title, onBackPress, actions, elevation) }
        val body = @Composable {
            Column(modifier = Modifier.verticalScroll(state = scrollState)) {
                content()
            }
        }

        SubcomposeLayout { constraints ->
            val layoutWidth = constraints.maxWidth
            val layoutHeight = constraints.maxHeight
            val looseConstraints = constraints.copy(minWidth = 0, minHeight = 0)

            layout(layoutWidth, layoutHeight) {
                val topBarPlaceables = subcompose(AppBarContent.AppBar, topBar).map {
                    it.measure(looseConstraints)
                }
                val topBarHeight = topBarPlaceables.maxByOrNull { it.height }?.height ?: 0
                val bodyContentHeight = layoutHeight - topBarHeight

                val bodyContentPlaceables = subcompose(AppBarContent.MainContent) {
                    body()
                }.map { it.measure(looseConstraints.copy(maxHeight = bodyContentHeight)) }


                bodyContentPlaceables.forEach {
                    it.place(0, topBarHeight)
                }
                topBarPlaceables.forEach {
                    it.place(0, 0)
                }
            }
        }
    }
}

@Composable
fun BackArrow(onclick: () -> Unit) {
    IconButton(onClick = { onclick() }) {
        Icon(imageVector = Icons.Default.ArrowBack, "Back Arrow")
    }
}

@Composable
private fun AppBar(
    title: String = "",
    onBackPress: (() -> Unit)? = null,
    actions: @Composable RowScope.() -> Unit = {},
    elevation: Dp
) {

    var navigationIcon: @Composable (() -> Unit)? = null
    onBackPress?.let {
        navigationIcon = { BackArrow { onBackPress.invoke() } }
    }

    Surface(
        color = MaterialTheme.colors.background,
        contentColor = MaterialTheme.colors.onBackground,
        elevation = elevation,
        shape = RectangleShape
    ) {
        Box(
            contentAlignment = Alignment.Center,
            modifier = Modifier.fillMaxWidth().padding(AppBarDefaults.ContentPadding).height(AppBarHeight)
        ) {
            navigationIcon?.let {
                Row(TitleIconModifier.align(Alignment.CenterStart), verticalAlignment = Alignment.CenterVertically) {
                    CompositionLocalProvider(
                        LocalContentAlpha provides ContentAlpha.high,
                        content = it
                    )
                }
            }

            Row(
                horizontalArrangement = Arrangement.Center,
                modifier = Modifier.fillMaxWidth(0.5f).fillMaxHeight(),
                verticalAlignment = Alignment.CenterVertically
            ) {
                Text(
                    text = title,
                    style = MaterialTheme.typography.h4,
                    textAlign = TextAlign.Center
                )
            }

            CompositionLocalProvider(LocalContentAlpha provides ContentAlpha.medium) {
                Row(
                    Modifier.align(Alignment.CenterEnd).fillMaxHeight(),
                    horizontalArrangement = Arrangement.End,
                    verticalAlignment = Alignment.CenterVertically,
                    content = actions
                )
            }

        }
    }

}

private val AppBarHorizontalPadding = 4.dp

private val TitleIconModifier = Modifier.fillMaxHeight().width(72.dp - AppBarHorizontalPadding)

private val AppBarHeight = 56.dp

enum class AppBarContent {
    AppBar,
    MainContent
}

关于android - Jetpack Compose 中是否有类似 AppBarLayout 的 "liftOnScroll"属性的东西?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/68149115/

相关文章:

android - Jetpack Compose 中的自定义形状尺寸

android - Android 设备选择器窗口目标栏中的橙色三角形是什么意思?

android - Facebook SDK + SlidingMenu SDK = Jar 不匹配!修复你的依赖

c# - 使用 linq to xml 从 XML 文档中获取 XElements 列表的 XElements 列表

java - 如何合并两个View?

android - Jetpack Compose RememberSwipeableState 回收问题

android - Jetpack Compose 和 Compose Navigation 如何处理 Android Activity ?

Android - 如何在以编程方式加载或保存 JPEG 文件时获取或设置(打印)DPI(每英寸点数)?

android - 在两个 View 之间沿着手指画线(ImageViews)

c++ - libxml2 sax 解析器 - 提取文本节点