androidandroid-studiokotlinandroid-viewpagerandroid-jetpack-compose

How to Implement Fade In / Fade Out Animation in Horizontal Pager Android Compose


Iam designing a Horizontal Pager in Android Jetpack Compose using googles accompanist Pager (implementation "com.google.accompanist:accompanist-pager:0.24.2-alpha"). I Implement this Horizontal Pager Correctly. But I want to change the default Animation of pager from horizontal left/ right swipe to fadein/ fadeout animation. Iam new to compose and i didn't find any useful resources in the internet. If anyone knows this help me to find the correct solutions. Thanks in Advance.

val pagerState = rememberPagerState()
    HorizontalPager(count = 3, state = pagerState
    ) { pagePosition ->
            PagerScreen(onBoardingData = onBoardingDataList[pagePosition])
    }

Here PagerScreen is a composable function for each screen.

Like this Gif I want fadein / fadeout for horizontal Pager


Solution

  • I'm not sure if there's a better solution using the HorizontalPager, so I did this solution using swipeable modifier.

    @ExperimentalMaterialApi
    @Composable
    fun SwipeableSampleScreen5() {
        val pages = listOf(
            596 to Color(203, 41, 61),
            801 to Color(107, 0, 141),
            492 to Color(40, 38, 149),
            718 to Color(56, 144, 244),
            550 to Color(60, 149, 159)
        )
        val swipeableState = rememberSwipeableState(0)
    
        // This Box is only to get the screen's width
        BoxWithConstraints(Modifier.fillMaxWidth()) {
            val widthPx = with(LocalDensity.current) {
                maxWidth.toPx()
            }
            // Each anchor of the swipeable is the index * screen width
            val anchors = remember(pages) {
                List(pages.size) { index ->
                    -(index * widthPx) to index
                }.toMap()
            }
            // This Box is capturing the swipe gesture
            Box(
                modifier = Modifier
                    .fillMaxSize()
                    .swipeable(
                        state = swipeableState,
                        anchors = anchors,
                        thresholds = { _, _ -> FractionalThreshold(0.5f) },
                        orientation = Orientation.Horizontal,
                    )
            ) {
                // swipeableState provides the current index and the next index
                val currentIndex = swipeableState.currentValue
                val nextIndex = swipeableState.progress.to
    
                // This Box is behind and will display the nextValue
                Box(
                    Modifier
                        // graphicsLayer is applied to the content
                        .graphicsLayer { 
                            alpha = 1f
                        },
                ) {
                    Box(
                        Modifier
                            .fillMaxSize()
                            .background(pages[nextIndex].second),
                        contentAlignment = Alignment.Center
                    ) {
                        Text(
                            text = pages[nextIndex].first.toString(),
                            style = MaterialTheme.typography.h1.copy(color = Color.White),
                        )
                    }
                }
    
                // This Box is showing the current value which will change 
                // the alpha during the swiping
                Box(
                    Modifier
                        .graphicsLayer {
                            alpha = 1f - swipeableState.progress.fraction
                        },
                ) {
                    Box(
                        Modifier
                            .fillMaxSize()
                            .background(pages[currentIndex].second),
                        contentAlignment = Alignment.Center
                    ) {
                        Text(
                            text = pages[currentIndex].first.toString(),
                            style = MaterialTheme.typography.h1.copy(color = Color.White),
                        )
                    }
                }
            }
        }
    }
    

    The solution is commented, but for a better understanding this article helped me a lot.

    Here's the result:

    enter image description here

    You can find the full source here.