【问题标题】:Is there something like AppBarLayout's "liftOnScroll" property in Jetpack Compose?Jetpack Compose 中是否有类似 AppBarLayout 的“liftOnScroll”属性?
【发布时间】:2021-06-28 21:15:00
【问题描述】:

AppBarLayout 中的属性app:liftOnScroll="true" 允许在滚动与app:layout_behavior="@string/appbar_scrolling_view_behavior" 关联的视图(通常是RecyclerView 或任何带有ScrolelView)。

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

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

【问题讨论】:

    标签: android xml android-jetpack-compose


    【解决方案1】:

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

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2021-01-05
      • 2021-08-02
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-04-13
      相关资源
      最近更新 更多