Passer de Swipeable à AnchoredDraggable

Swipeable est une API Material de Compose qui vous aide à créer des composants peut être balayé pour passer d'un état à l'autre, par exemple dans des bottom sheets, des panneaux ou balayer l'écran pour fermer. Pour mieux prendre en charge les cas d'utilisation avancés, comme les ancres qui dépend de la taille d'un composant, un successeur a été publié dans Compose-Foundation 1.6.0-alpha01: AnchoredDraggable. AnchoredDraggable est une API Foundation permettant de créer des composants déplaçables avec des états ancrés, en bas de l'écran, dans des panneaux ou en balayant l'écran pour fermer.

Les API Swipeable de Material ont été abandonnées au profit de Foundations AnchoredDraggable et sera supprimé dans une prochaine version. Ce guide explique comment migrer des API Swipeable vers AnchoredDraggable.

Migrer SwipeableState vers AnchoredDraggableState

Commencez par identifier les modifications apportées à votre conteneur d'état. AnchoredDraggableState ne peuvent pas être héritées, et le décalage est représenté par Float.NaN avant est initialisé.

Mettre à jour votre conteneur d'état

AnchoredDraggableState est une classe finale, ce qui signifie qu'elle ne peut pas être héritée. Si votre composant existant hérite de SwipeableState, mettez à jour votre conteneur d'état pour conserver une référence à AnchoredDraggableState au lieu de en héritant:

À faire glisser

class MySwitchState: SwipeableState()

AncrageDraggable

class MySwitchState {
    private val anchoredDraggableState = AnchoredDraggableState(...)
}

Étant donné que votre conteneur d'état n'hérite plus de SwipeableState, vous vous devrez peut-être exposer des API vous-même. Les API les plus courantes que vous pouvez utiliser sont offset, progress, currentValue et targetValue.

Accéder au décalage

Contrairement à Swipeable, le offset de AnchoredDraggableState aura lieu Float.NaN avant avant qu'elle ne soit initialisée. Dans AnchoredDraggable, les ancres peuvent être transmises à constructeur de AnchoredDraggableState ou mis à jour via AnchoredDraggableState#updateAnchors Le fait de transmettre les ancres à Le constructeur de AnchoredDraggableState initialise immédiatement le décalage.

Si les ancres dépendent de la mise en page ou sont susceptibles de changer, utilisez AnchoredDraggableState#updateAnchors pour éviter de recréer l'état lorsque les ancres changent.

Si vous utilisez updateAnchors, le décalage est de Float.NaN avant la transmission de les ancres à updateAnchors. Pour éviter de transmettre accidentellement Float.NaN à utilisez AnchoredDraggableState#requireOffset pour exiger que le offset a été initialisé lors de sa lecture. Cela vous aide à détecter d'incohérences ou de bugs possibles dès le début.

@Composable
fun AnchoredDraggableBox() {
    val state = remember { AnchoredDraggableState(...) }
    val density = LocalDensity.current
    val anchors = remember { DraggableAnchors { ... } }
    SideEffect {
        state.updateAnchors(anchors)
    }
    Box(
        Modifier.offset { IntOffset(x = state.requireOffset(), y = 0) }
    }
}

Migrer Modifier.swipeable vers Modifier.anchoredDraggable

Modifier.anchoredDraggable() remplace Modifier.swipeable. Un peu des paramètres de Modifier.swipeable() ont été déplacés vers AnchoredDraggableState directement, comme décrit dans les sections suivantes.

Définir des ancres

Définissez les ancres à l'aide de la méthode de compilateur DraggableAnchors. Ensuite, transmettez aux AnchoredDraggableState#updateAnchors ou AnchoredDraggableState constructeur:

Constructeur

enum class DragValue { Start, Center, End }

@Composable
fun AnchoredDraggableBox() {
    val anchors = DraggableAnchors {
        Start at -100.dp.toPx()
        Center at 0f
        End at 100.dp.toPx()
    }
    val state = remember {
        AnchoredDraggableState(anchors = anchors)
    }
    Box(
        Modifier.offset { IntOffset(x = state.requireOffset(), y = 0) }
    )
}

updateAnchors

enum class DragValue { Start, Center, End }

@Composable
fun AnchoredDraggableBox() {
    val state = remember { AnchoredDraggableState(...) }
    val density = LocalDensity.current
    val anchors = with (density) {
        DraggableAnchors {
            Start at -100.dp.toPx()
            Center at 0f
            End at 100.dp.toPx()
        }
    }
    SideEffect {
        state.updateAnchors(anchors)
    }
    Box(
        Modifier.offset { IntOffset(x = state.requireOffset(), y = 0) }
    )
}

Si les ancres sont statiques, transmettez-les au constructeur. Si elles dépendent ou ne sont pas statiques, utilisez updateAnchors.

Définir des seuils de position

Le type et le nom du paramètre de seuil ont changé. Au lieu d'avoir un interface ThresholdConfig distincte, AnchoredDraggableState a une un paramètre positionalThreshold qui accepte une fonction lambda qui renvoie le la position du seuil. Par exemple, un seuil positionnel de 50% pourrait être exprimé comme suit:

val anchoredDraggableState = AnchoredDraggableState(
    positionalThreshold = { distance -> distance * 0.5f },
    ...
)

Un seuil positionnel de 56dp peut être exprimé comme suit:

val density = LocalDensity.current
val anchoredDraggableState = AnchoredDraggableState(
    positionalThreshold = { with(density) { 56.dp.toPx() } },
    ...
)

Définir des seuils de vitesse

Les seuils de vitesse sont également transmis au constructeur de AnchoredDraggableState, et également exprimé sous la forme d'un lambda:

val density = LocalDensity.current
val anchoredDraggableState = AnchoredDraggableState(
    velocityThreshold = { with(density) { 125.dp.toPx() } },
    ...
)

Modifications apportées à la surface de l'API

Vous trouverez ci-dessous un aperçu des modifications apportées à la surface de l'API.

AnchoredDraggableState

SwipeableState

AnchoredDraggableState

open class SwipeableState(initialValue: T, animationSpec: AnimationSpec = …, confirmStateChange: (T) -> Boolean = …)

class AnchoredDraggableState( initialValue: T, animationSpec: AnimationSpec = …, confirmValueChange: (T) -> Boolean = …, positionalThreshold: Density.(Float) -> Float = …, velocityThreshold: Dp = …)

offset: State

offset: Float
requireOffset()

progress: SwipeProgress

progress: Float [0f..1f]

currentValue: T

currentValue: T

targetValue: T

targetValue: T

direction: Float [-1f, 0f, 1f]

N/A

suspend animateTo(
targetValue: T,
anim: AnimationSpec = …)

suspend animateTo(
targetState: T,
velocity: Float =
lastVelocity)

suspend snapTo(targetValue: T)

suspend snapTo(targetValue: T)

performDrag(delta: Float)

dispatchRawDelta(delta: Float)

suspend performFling(velocity: Float)

suspend settle(velocity: Float)

isAnimationRunning: Boolean

isAnimationRunning: Boolean

lastVelocity: Float

Modifier.anchoredDraggable

Modifier.swipeable

Modifier.anchoredDraggable

state: SwipeableState

state: AnchoredDraggableState

anchors: Map

AnchoredDraggableState#updateAnchors
or

AnchoredDraggableState#constructor

orientation: Orientation

orientation: Orientation

enabled: Boolean = true

enabled: Boolean = true

reverseDirection: Boolean = false

reverseDirection: Boolean = false

interactionSource: MutableInteractionSource? = null

interactionSource: MutableInteractionSource? = null

thresholds: (from: T, to: T) -> ThresholdConfig = FixedThreshold(56.dp)

Transmis au constructeur AnchoredDraggableState en tant que positionalThreshold

resistance: ResistanceConfig? = …

Pas encore compatible. Consultez b/288084801 pour connaître l'état le plus récent.

velocityThreshold: Dp = 125.dp

Transmis au constructeur AnchoredDraggable