Context
I am in the process of making a custom component that is similar to the BannerAd view. In my case, it is a fairly simple component that uses a HorizontalPager
to display images. Here are the pertinent features I want my component to implement:
- The pager will scroll automatically every couple of seconds.
- If the user is pressing/dragging the image displayed the pager will temporarily stop the automatic scrolling.
Question
I have found two different ways in which this can be implemented and was wondering if there was a best practice for these types of 'design' problems.The first way is to observe only the interactionState
of the Image
composable inside the HorizontalPager
. The only type of Interaction
passed from the interactionSource
state is of type PressInteraction
(Press, Release, Cancel).
The second way is to observe the interactionState
of the Image
composable and the drag state of the pager. We still need to observe the interactionState
of the Image
as the pager does not provide information about state changes to PressInteraction
(only DragInteraction
is handled).
Approach number 1 seems simpler, where we seem to be implicitly relying on the fact that a drag event is a subset of a press event i.e. it's not possible to drag the banner without pressing an item first but approach number 2 seems more explicit in the type of events we are handling. Aside from readability, could performance be a consideration? Are there any other aspects I have neglected, which I should be concerned about? Or is there a completely different approach which would be better than both?
Code
Approach number 1@Composable
fun FoundationBanner(
drawableResources: List<Int>,
) {
val pagerState = rememberPagerState(0)
val interactionSource = remember { MutableInteractionSource() }
val interactionState by interactionSource.interactions.collectAsState(initial = null)
LaunchedEffect(key1 = interactionState) {
if (interactionState !is PressInteraction.Press) {
while (true) {
delay(2000)
pagerState.animateScrollToPage((pagerState.currentPage + 1) % drawableResources.size)
}
}
}
HorizontalPager(
state = pagerState,
pageCount = drawableResources.size,
) { page ->
Image(
painter = painterResource(id = drawableResources[page]),
contentDescription = null,
modifier = Modifier.clickable(interactionSource, null) {}
)
}
}
Approach number 2
@Composable
fun FoundationBanner(
drawableResources: List<Int>,
) {
val pagerState = rememberPagerState(0)
val pagerIsDragged by pagerState.interactionSource.collectIsDraggedAsState()
val interactionSource = remember { MutableInteractionSource() }
val interactionState by interactionSource.interactions.collectAsState(initial = null)
LaunchedEffect(key1 = interactionState, key2 = pagerIsDragged) {
if (!pagerIsDragged && interactionState !is PressInteraction.Press) {
while (true) {
delay(2000)
pagerState.animateScrollToPage((pagerState.currentPage + 1) % drawableResources.size)
}
}
}
HorizontalPager(
state = pagerState,
pageCount = drawableResources.size,
) { page ->
Image(
painter = painterResource(id = drawableResources[page]),
contentDescription = null,
contentScale = ContentScale.Crop,
modifier = Modifier.clickable(interactionSource, null) {}
)
}
}