Jetpack Compose 中是否有类似 AppBarLayout 的“liftOnScroll”属性?

Mic*_*ato 5 xml android android-jetpack-compose

AppBarLayout 中的属性允许当关联的视图滚动时(通常是 a或 a 内的任何内容app:liftOnScroll="true"),视图会显示为抬起的状态(基本上在底部添加一条小线的高度阴影)。app:layout_behavior="@string/appbar_scrolling_view_behavior"RecyclerViewScrolelView

Jetpack Compose 中有类似的东西吗?我无法找到兼容的行为,无论是与TopAppBar常规还是与常规Text(在其任何参数或修饰符中)。

简而言之 - 有没有什么方法可以提升类似工具栏的视图,但只有当底层列表/可滚动内容滚动时(而不是在顶部)?

Vyg*_*s B 2

不幸的是它还不支持。但您可以自己创建它。您需要使用可滚动组件包装主要内容,并根据主要内容的滚动状态对 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
}
Run Code Online (Sandbox Code Playgroud)