I have a full screen horizontal pager (using Accom...
# compose-wear
b
I have a full screen horizontal pager (using Accompanist's
HorizontalPager
), and the default Activity's swipe to dismiss behavior "vaguely works" 🙂 By that I mean, if I swipe with a quick enough gesture, it works. If I swipe slowly, it doesn't. (not using
NavHost
or
SwipeToDismissBox
) Any idea/pointers?
j
To be honest that isn't a configuration I have tried, we tend to use SwipeToDismissBox and edgeSwipe. If you want to send a reproducible case I will try it on couple of devices
b
Thanks a lot! I'll do that.
y
+1 to a repro case. Are you using the edgeSwipeToDismiss modifier?
Just realised that only applies to a SwipeToDismissBox, or SwipeDismissableNavHost
b
All right, issue filed here with a repro project
s
Thanks for the repro project - we can see the issue, both on the emulator and on devices. The issue seems to be that the System swipe-to-dismiss gesture handling is fighting with the HorizontalPager gesture handling. As a workaround, if you put a SwipeToDismissBox around the MainScreenContent, and add Modifier.edgeSwipeToDismiss to the HorizontalPager, then the swipe gesture is solid (and you can edge-swipe on other pages to dismiss, not just page zero). There is still an issue that the content flashes back full screen after it's been dismissed - will look into that.
Copy code
@AndroidEntryPoint
class MainActivity : ComponentActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContent {
            MainScreen( { ActivityCompat.finishAffinity(this) })
        }
    }
}

@Composable
private fun MainScreen(onDismissed: () -> Unit) {
    CineTodayTheme {
        Scaffold {
            val swipeToDismissBoxState = rememberSwipeToDismissBoxState()
            SwipeToDismissBox(onDismissed = onDismissed, state = swipeToDismissBoxState) { bg ->
                if (!bg) MainScreenContent(swipeToDismissBoxState)
            }
        }
    }
}

@OptIn(ExperimentalPagerApi::class)
@Composable
private fun MainScreenContent(state: SwipeToDismissBoxState) {
    val pagerState: PagerState = rememberPagerState()
    HorizontalPager(
        count = PAGE_COUNT,
        modifier = Modifier
            .fillMaxSize()
            .edgeSwipeToDismiss(state),
        state = pagerState,
    ) { page ->
        when (page) {
            0 -> PageScreen(0)
            1 -> PageScreen(1)
            2 -> PageScreen(2)
        }
    }
}
b
Thanks a lot for looking into this! 🙏 I'll try
SwipeToDismissBox
a bit later today.
s
Ah, turns out that in this case, we need to write our own LaunchedEffect, so don't pass onDismissed into the SwipeToDismissBox (the default resets the offset position of the screen, which we don't want to do in this case). This gets rid of the spurious flash when dismissed:
Copy code
private fun MainScreen(onDismissed: () -> Unit = {}) {
    CineTodayTheme {
        Scaffold {
            val state = rememberSwipeToDismissBoxState()
            SwipeToDismissBox(state = state) { bg ->
                if (!bg ) MainScreenContent(state)
            }
            LaunchedEffect(state.currentValue) {
                if (state.currentValue == SwipeToDismissValue.Dismissed) {
                    onDismissed()
                }
            }
        }
    }
}
b
Very cool 👍 I haven't tried yet but I am guessing that you won't see the previous activity under this one though, right?
I just tried, and indeed, but making the activity translucent does the trick:
Copy code
<style name="Theme.CineToday" parent="@android:style/Theme.DeviceDefault">
        <item name="android:windowBackground">@android:color/transparent</item>
    </style>
209 Views