I want to achieve the following effect: Three sections - image, header, and text. When I scroll up, I want the image section to shrink until its gone, the two lower sections to move up and occupy the freed up space, the header to become a sticky header at the top, and then the text scroll to kick in last.
My first attempt was with placing Modifier.verticalScroll both in the overall container and the child text, have the container view scroll first, shrink the image section until completely hidden, and then stop the container scroll (based on it reaching a certain scroll value) and then have the text scroll kick in. So, without going into specific detail, the principle was:
Container: .verticalScroll(scrollState, scrollState.value <= 99)
Child text: .verticalScroll(scrollState, scrollState.value > 99)
However, when I disable the container scroll, it also disables the child scroll.
So my next attempt was with Modifier.Scrollable. Per Jetpack Compose documentation:
The scrollable modifier differs from the scroll modifiers in that scrollable detects the scroll gestures, but does not offset its contents.The scrollable modifier does not affect the layout of the element it is applied to. This means that any changes to the element layout or its children must be handled through the delta provided by ScrollableState.
So that means the control is in our hands. This seems to be working (code below shown in action in the gif), but I am wondering if this is really the right way to go about it, or if there is a better way? (I still need to figure out exact offsets, but the q is more about the approach in general)
@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)
}
}
}