MotionCarousel

Functions summary

Unit
@Composable
MotionCarousel(
    motionScene: MotionScene,
    initialSlotIndex: Int,
    numSlots: Int,
    backwardTransition: String,
    forwardTransition: String,
    slotPrefix: String,
    showSlots: Boolean,
    content: MotionCarouselScope.() -> Unit
)

Implements an horizontal Carousel of n elements, driven by drag gestures and customizable through a provided MotionScene.

Functions

@Composable
fun MotionCarousel(
    motionScene: MotionScene,
    initialSlotIndex: Int,
    numSlots: Int,
    backwardTransition: String = "backward",
    forwardTransition: String = "forward",
    slotPrefix: String = "slot",
    showSlots: Boolean = false,
    content: MotionCarouselScope.() -> Unit
): Unit

Implements an horizontal Carousel of n elements, driven by drag gestures and customizable through a provided MotionScene.

Usage

-----

val cardsExample = arrayListOf(...)

MotionCarousel(motionScene...) { items(cardsExample) { card -> SomeCardComponent(card) } }

or if wanting to use parameters in your components that are defined in the MotionScene:

MotionCarousel(motionScene...) { itemsWithProperties(cardsExample) { card, properties -> SomeCardComponent(card, properties) } }

Note

----

It is recommended to encapsulate the usage of MotionCarousel:

fun MyCarousel(content: MotionCarouselScope.() -> Unit) { val motionScene = ... MotionCarousel(motionScene..., content) }

Mechanism overview and MotionScene architecture

-----------------------------------------------

We use 3 different states to represent the Carousel: "previous", "start", and "next". A horizontal swipe gesture will transition from one state to the other, e.g. a right to left swipe will transition from "start" to "next".

We consider a scene containing several "slots" for the elements we want to display in the Carousel. In an horizontal carousel, the easiest way to think of them is as an horizontal list of slots.

The overall mechanism thus works by moving those "slots" according to the gesture, and then mapping the Carousel's elements to the corresponding slots as we progress through the list of elements.

For example, let's consider using a Carousel with 3 slots 1 and 2, with 1 the center slot being the only visible one during the initial state "start" (| and | representing the screen borders) and 0 being outside of the screen on the left and 2 outside of the screen on the right:

start 0 | 1 | 2

We can setup the previous state in the following way:

previous | 0 | 3

And the next state like:

next 1 | 2 |

All three states together allowing to implement the Carousel motion we are looking for:

previous | 0 | 3 start 0 | 1 | 2 next 1 | 2 |

At the end of the swipe gesture, we instantly move back to the start state:

start 0 | 1 | 2 -> gesture starts next 1 | 2 | -> gesture ends start 0 | 1 | 2 -> instant snap back to start state

After the instant snap, we update the elements actually displayed in the slots. For example, we can start with the elements {a}, {b} and {c} assigned respectively to the slots 0, 1 and 2. After the swipe the slots will be reassigned to {b}, {c} and {d}:

start 0:{a} | 1:{b} | 2:{d} -> gesture starts next 0:{a} 1:{b} | 2:{c} | -> gesture ends start 0:{a} | 1:{b} | 2:{c} -> instant snap back to start state start 0:{b} | 1:{c} | 2:{d} -> repaint with reassigned elements

In this manner, the overall effect emulate an horizontal scroll of a list of elements.

A similar mechanism is applied the left to right gesture going through the previous state.

Starting slot

-------------

In order to operate, we need a list of slots. We retrieve them from the motionScene by adding to the slotPrefix an index number. As the starting slot may not be the first one in the scene, we also need to be able to specify a startIndex.

Note that at the beginning of the Carousel, we will not populate the slots that have a lower index than startIndex, and at the end of the Carousel, we will not populate the slots that have a higher index than startIndex.

Parameters
initialSlotIndex: Int

the slot index that holds the current element

numSlots: Int

the number of slots in the scene

backwardTransition: String = "backward"

the name of the previous transition (default "previous")

forwardTransition: String = "forward"

the name of the next transition (default "next")

slotPrefix: String = "slot"

the prefix used for the slots widgets in the scene (default "card")

showSlots: Boolean = false

a debug flag to display the slots in the scene regardless if they are populated

content: MotionCarouselScope.() -> Unit

the MotionCarouselScope we use to map the elements to the slots