Esegui la migrazione da Scorrimento a AnchoredTrascinabile

Swipeable è un'API Compose Material che ti aiuta a creare componenti che possono essere spostati tra stati discreti, come fogli inferiori, riquadri a scomparsa o swipe-to-dismiss. Per supportare meglio i casi d'uso avanzati, come i punti fissi che dipendono dalle dimensioni di un componente, è stato pubblicato un successore in Compose-Foundation 1.6.0-alpha01: AnchoredDraggable. AnchoredDraggable è un'API Foundation per la creazione di componenti trascinabili con stati ancorati, come fogli inferiori, riquadri a scomparsa o swipe-to-dismiss.

Le API Swipeable di Material sono state ritirate a favore di AnchoredDraggable di Foundation e verranno rimosse in una release futura. Questa guida descrive come eseguire la migrazione dalle API Swipeable a AnchoredDraggable.

Eseguire la migrazione di SwipeableState a AnchoredDraggableState

Inizia identificando le modifiche al contenitore di stato. AnchoredDraggableState non è possibile ereditare da e l'offset è rappresentato come Float.NaN prima che venga inizializzato.

Aggiornare il contenitore di stato

AnchoredDraggableState è una classe finale, il che significa che non può essere ereditata. Se il componente esistente eredita da SwipeableState, aggiorna il contenitore di stato in modo che contenga un riferimento a AnchoredDraggableState anziché ereditare da esso:

Swipeable

class MySwitchState: SwipeableState()

AnchoredDraggable

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

Poiché il contenitore di stato non eredita più da SwipeableState, potresti dover esporre le API autonomamente. Le API più comuni che puoi utilizzare sono offset, progress, currentValue e targetValue.

Accedere all'offset

A differenza di Swipeable, AnchoredDraggableState's offset è Float.NaN prima dell'inizializzazione. In AnchoredDraggable, i punti fissi possono essere passati al costruttore di AnchoredDraggableState's o aggiornati tramite AnchoredDraggableState#updateAnchors. Il passaggio dei punti fissi al costruttore di AnchoredDraggableState inizializza immediatamente l'offset.

Se i punti fissi dipendono dal layout o potrebbero cambiare, utilizza AnchoredDraggableState#updateAnchors per evitare di ricreare lo stato quando i punti fissi cambiano.

Se utilizzi updateAnchors, l'offset sarà Float.NaN prima di passare i punti di ancoraggio a updateAnchors. Per evitare di passare accidentalmente Float.NaN a componenti, utilizza AnchoredDraggableState#requireOffset per richiedere che l' offset sia stato inizializzato durante la lettura. In questo modo puoi rilevare le incoerenze o i possibili bug in anticipo.

@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) }
    }
}

Eseguire la migrazione di Modifier.swipeable a Modifier.anchoredDraggable

Modifier.anchoredDraggable() sostituisce Modifier.swipeable. Alcuni parametri di Modifier.swipeable() sono stati spostati direttamente in AnchoredDraggableState, come descritto nelle sezioni seguenti.

Definire i punti fissi

Definisci i punti fissi utilizzando il DraggableAnchors metodo di creazione. Poi, passali a AnchoredDraggableState#updateAnchors o al costruttore di AnchoredDraggableState:

Costruttore

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) }
    )
}

Se i punti fissi sono statici, passali al costruttore. Se dipendono dal layout o non sono statici, utilizza updateAnchors.

Definire le soglie posizionali

Il tipo e il nome del parametro delle soglie sono cambiati. Anziché avere un' interfaccia ThresholdConfig separata, AnchoredDraggableState ha un positionalThreshold parametro che accetta una funzione lambda che restituisce la posizione della soglia. Ad esempio, una soglia posizionale del 50% potrebbe essere espressa come:

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

Una soglia posizionale di 56dp potrebbe essere espressa come:

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

Definire le soglie di velocità

Le soglie di velocità vengono passate anche al costruttore di AnchoredDraggableState e vengono espresse anche come lambda:

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

Modifiche alla superficie dell'API

Di seguito è riportata una panoramica delle modifiche alla superficie dell'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/D

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)

Passato al costruttore di AnchoredDraggableState come positionalThreshold

resistance: ResistanceConfig? = …

Non ancora supportato. Per lo stato più recente, consulta b/288084801.

velocityThreshold: Dp = 125.dp

Passato al costruttore di AnchoredDraggable