繁体   English   中英

Modifier.Scrollable 在 Android Jetpack Compose 中

[英]Modifier.Scrollable in Android Jetpack Compose

我想达到以下效果:三个部分-图像,header,和文本。 当我向上滚动时,我希望图像部分缩小直到消失,两个较低的部分向上移动并占用释放的空间,header 变成顶部的粘性 header,然后文本滚动到最后.

寻求的效果

我的第一次尝试是将Modifier.verticalScroll放在整个容器和子文本中,首先让容器视图滚动,缩小图像部分直到完全隐藏,然后停止容器滚动(基于它达到某个滚动值)然后让文本滚动启动。因此,无需详细说明,原则是:

Container: .verticalScroll(scrollState, scrollState.value <= 99)
Child text: .verticalScroll(scrollState, scrollState.value > 99)

但是,当我禁用容器滚动时,它也会禁用子滚动。

所以我的下一个尝试是Modifier.Scrollable 根据 Jetpack Compose 文档:

可滚动修饰符与滚动修饰符的不同之处在于,可滚动可检测滚动手势,但不会偏移其内容。可滚动修饰符不会影响其应用到的元素的布局。 这意味着对元素布局或其子元素的任何更改都必须通过 ScrollableState 提供的增量来处理。

这意味着控制权在我们手中。 这似乎有效(下面的代码在 gif 中显示),但我想知道这是否真的是 go 的正确方法,或者是否有更好的方法? (我仍然需要找出确切的偏移量,但 q 更多的是关于一般方法)

@Composable
fun Detail(){
    val scrollState = rememberScrollState()
    var offset by remember { mutableStateOf(0f) }

    Column(
        modifier = Modifier
            .scrollable(
                orientation = Orientation.Vertical,
                state = rememberScrollableState { delta ->
                    offset += delta
                    delta
                }
            )
    ) {
        Box(
            modifier = Modifier
                .fillMaxWidth()
                .size(250.dp - (-offset).dp),
            contentAlignment = Alignment.Center
        ) {
            Image(
                painter = rememberImagePainter(
                    data =  "https://www.gstatic.com/webp/gallery/1.jpg",
                ),
                alignment = Alignment.TopCenter,
                contentDescription = null,
                contentScale = ContentScale.Crop,
                modifier = Modifier
                    .size(225.dp - (-offset).dp)
                    .clip(CircleShape)
            )
        }
            Column() {
                    Text("This is a header",
                        Modifier
                            .padding(20.dp, 10.dp)
                            .fillMaxWidth()
                            .align(Alignment.CenterHorizontally),
                        textAlign = TextAlign.Center,
                        style = MaterialTheme.typography.h5)
                    Text("Start here...." + "lorem ipsum ".repeat(120),
                        Modifier
                            .padding(20.dp, 10.dp, 20.dp, 5.dp)
                             .verticalScroll(scrollState, offset < -40)
                            .align(Alignment.CenterHorizontally),
                        lineHeight = 20.sp,
                        style = MaterialTheme.typography.body2)
            }
    }
}

感谢@nglauber提供的评论和这个答案的链接 - 一个类似的问题,我能够计算出我想要的效果。 我最初的解决方案也有效,但我认为这个更优雅,并且 - 最重要的是 - 提供了更平滑的效果 - 所以继续使用它。

回顾一下,我需要三个部分 - 图像、header 和文本。 当我向上滚动时,我希望图像部分缩小直到消失,两个较低的部分向上移动并占用释放的空间,header 在顶部变成粘性 header,然后文本滚动最后开始。

所以这是我从链接答案中修改后的代码,以达到我想要的结果:

@OptIn(ExperimentalFoundationApi::class)
@Composable
fun CollapsingEffectScreen() {

    val lazyListState = rememberLazyListState()
    var scrolledY = 0f
    var previousOffset = 0
    LazyColumn(
        Modifier.fillMaxSize(),
        lazyListState,
        verticalArrangement = Arrangement.Center,
        horizontalAlignment = Alignment.CenterHorizontally
    ) {
        item {
            Modifier.fillMaxWidth()
            Image(
                painter = rememberImagePainter(
                    data =  "https://www.gstatic.com/webp/gallery/1.jpg",
                ),
                alignment = Alignment.Center,
                contentDescription = null,
                contentScale = ContentScale.Crop,
                modifier = Modifier
                    .graphicsLayer {
                        scrolledY += lazyListState.firstVisibleItemScrollOffset - previousOffset
                        translationY = scrolledY * 0.5f
                        scaleX = 1/((scrolledY * 0.01f) + 1f)
                        scaleY = 1/((scrolledY * 0.01f) + 1f)
                        previousOffset = lazyListState.firstVisibleItemScrollOffset
                    }
                    .size(225.dp)
                    .padding(20.dp)
                    .fillMaxSize()
                    .clip(CircleShape)
            )
        }
        stickyHeader {
            Text(
                text = "this is header ",
                Modifier
                    .background(Color.White)
                    .height(80.dp)
                    .fillMaxWidth()
                    .padding(20.dp),
                textAlign = TextAlign.Center,
                style = MaterialTheme.typography.h5
            )
        }
        items(1) {
            Text(
                text = "this is body text  ".repeat(200),
                Modifier
                    .background(Color.White)
                    .fillMaxWidth()
                    .padding(35.dp),
                lineHeight = 20.sp,
                style = MaterialTheme.typography.body2

            )
        }
    }
} 

在行动: 在此处输入图像描述

PS:反过来也很好用。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM