This is the fourth day of my participation in Gwen Challenge

There is currently a Chinese manual project for Jetpack Compose, which aims to help developers better understand and master the Compose framework. This article, written by myself, has been published in the handbook, welcome to refer to.

1. What can Swipeable do

Unlike the Draggable modifier, the swipeable modifier allows developers to animate components by setting anchor points. Swipeable is used for animations such as switches and for special effects such as pull-downs.

It is worth noting, however, that the swipeable modifier does not provide any default animation for the modified component, only information such as gesture offsets for the component. Developers can customize animation displays based on offsets and other modifiers.

2. Swipeable parameter list

To use the swipeable modifier, you need to pass in at least three parameters swipeableState, anchors, and orientation

SwipeableState: The offset information of the current gesture can be obtained by swipeableState

Anchors: Anchors that allow you to set the offset information that should correspond to different states

Orientation: Gesture orientation. The gesture orientation of the modified component can only be horizontal or vertical

Thresholds (commonly not required) : commonly used to customize the critical threshold of adsorption effect between different anchor points, commonly used FixedThreshold(Dp) and FractionalThreshold(Float), etc

fun <T> Modifier.swipeable(
    state: SwipeableState<T>,
    anchors: Map<Float, T>,
    orientation: Orientation,
    enabled: Boolean = true,
    reverseDirection: Boolean = false,
    interactionSource: MutableInteractionSource? = null,
    thresholds: (from: T.to: T) - >ThresholdConfig = { _, _ -> FixedThreshold(56.dp) },
    resistance: ResistanceConfig? = resistanceConfig(anchors.keys),
    velocityThreshold: Dp = VelocityThreshold
)
Copy the code

3. Swipeable example

In this section, we will use the swipeable modifier to complete a simple switch animation.

First we define two enumerations that describe the state of the switch and set the size of the switch.

We get the SwipeableState instance through the rememberSwipeableState method and set the initial state to status.close.

enum class Status{
    CLOSE, OPEN
}
var blockSize = 48.dp
var blockSizePx = with(LocalDensity.current) { blockSize.toPx() }
var swipeableState = rememberSwipeableState(initialValue = Status.CLOSE)
Copy the code

In our example, each state corresponds to an anchor point, and we need to declare a value for each anchor point, which is represented by a key-value pair.

At the same time, Compose knows the initial state number the developer wants.

var anchors = mapOf(
	0f to Status.CLOSE,
 	blockSizePx to Status.OPEN
)
Copy the code

We next describe thresholds for adsorption animation between anchors. We hope that from the closed state to the open state, the slider only needs to move more than 30% to automatically adsorb to the open state, and from the open state to the closed state, the slider needs to move more than 50% to automatically adsorb to the closed state.

Modifier.swipeable(
    state = swipeableState,
    anchors = mapOf(
        0f to Status.CLOSE,
        blockSizePx to Status.OPEN
    ),
    thresholds = { from, to ->
        if (from == Status.CLOSE) {
            FractionalThreshold(0.3 f)}else {
            FractionalThreshold(0.5 f)
        }
    },
    orientation = Orientation.Horizontal
)
Copy the code

Next, we can get the offset information through SwipeableState. We want the slider to move based on the offset, which is what we need to do with the offset descriptor in our example.

@ExperimentalMaterialApi
@Preview
@Composable
fun SwipeableDemo(a) {
    var blockSize = 48.dp
    var blockSizePx = with(LocalDensity.current) { blockSize.toPx() }
    var swipeableState = rememberSwipeableState(initialValue = Status.CLOSE)
    var anchors = mapOf(
        0f to Status.CLOSE,
        blockSizePx to Status.OPEN
    )
    Box(
        modifier = Modifier
            .size(height = blockSize, width = blockSize * 2)
            .background(Color.LightGray)
    ) {
        Box(
            modifier = Modifier
                .swipeable(
                    state = swipeableState,
                    anchors = mapOf(
                        0f to Status.CLOSE,
                        blockSizePx to Status.OPEN
                    ),
                    thresholds = { from, to ->
                        if (from == Status.CLOSE) {
                            FractionalThreshold(0.3 f)}else {
                            FractionalThreshold(0.5 f)
                        }
                    },
                    orientation = Orientation.Horizontal
                )
                .offset {
                    IntOffset(swipeableState.offset.value.toInt(), 0)
                }
                .size(blockSize)
                .background(Color.DarkGray)
        )
    }
}
Copy the code

4. Effect display