I am trying to create a parallax effect with a wide image lets say:
As you can see while going through the list white space appears on the right instead of the remaining image.
How do i do this properly?
CodePudding user response:
Image
is too smart and doesn't draw anything beyond the bounds. translationX
doesn't change the bound but only moves the view.
Here's how you can draw it manually:
val painter = painterResource(id = R.drawable.my_image_1)
Canvas(
modifier = Modifier
.fillMaxWidth()
.height(BG_IMAGE_HEIGHT)
) {
translate(
left = -parallaxOffset,
) {
with(painter) {
draw(Size(width = painter.intrinsicSize.aspectRatio * size.height, height = size.height))
}
}
}
I don't see your code that calculates parallaxOffset
, but just in case, I suggest you watch
CodePudding user response:
I'm leaving my solution here...
@Composable
private fun ListBg(
firstVisibleIndex: Int,
totalVisibleItems: Int,
firstVisibleItemOffset: Int,
itemsCount: Int,
maxWidth: Dp
) {
val density = LocalDensity.current
val firstItemOffsetDp =
with(density) { firstVisibleItemOffset.toDp() } / itemsCount
val hasNoScroll = itemsCount <= totalVisibleItems
val totalWidth = if (hasNoScroll) maxWidth else maxWidth * 2
val scrollableBgWidth = if (hasNoScroll) maxWidth else totalWidth - maxWidth
val scrollStep = scrollableBgWidth / itemsCount
val xOffset = if (hasNoScroll) 0.dp else -(scrollStep * firstVisibleIndex) - firstItemOffsetDp
Box(
Modifier
.wrapContentWidth(unbounded = true, align = Alignment.Start)
.offset(x = xOffset)
) {
Image(
painter = rememberAsyncImagePainter(
model = "https://placekitten.com/2000/400",
contentScale = ContentScale.FillWidth,
),
contentDescription = null,
alignment = Alignment.TopCenter,
modifier = Modifier
.height(232.dp)
.width(totalWidth)
)
}
}
@Composable
fun ListWithParallaxImageScreen() {
val lazyListState = rememberLazyListState()
val firstVisibleIndex by remember {
derivedStateOf {
lazyListState.firstVisibleItemIndex
}
}
val totalVisibleItems by remember {
derivedStateOf {
lazyListState.layoutInfo.visibleItemsInfo.size
}
}
val firstVisibleItemOffset by remember {
derivedStateOf {
lazyListState.firstVisibleItemScrollOffset
}
}
val itemsCount = 10
BoxWithConstraints(Modifier.fillMaxSize()) {
ListBg(firstVisibleIndex, totalVisibleItems, firstVisibleItemOffset, itemsCount, maxWidth)
LazyRow(state = lazyListState, modifier = Modifier.fillMaxSize()) {
items(itemsCount) {
Card(
backgroundColor = Color.LightGray.copy(alpha = .5f),
modifier = Modifier
.padding(16.dp)
.width(300.dp)
.height(200.dp)
) {
Text(
text = "Item $it",
Modifier
.padding(horizontal = 16.dp, vertical = 6.dp)
)
}
}
}
}
}
Here is the result: