Cómo migrar de Swipeable a AnchoredDraggable

Swipeable es una API de Compose Material que te ayuda a compilar componentes que se puede deslizar entre estados discretos, como hojas inferiores, paneles laterales o deslizar para descartar Para admitir mejor casos de uso avanzados, como anuncios fijos que depender del tamaño de un componente, se publicó un sucesor en Compose-Foundation 1.6.0-alpha01: AnchoredDraggable AnchoredDraggable es una API de Foundation para crear componentes arrastrables con estados anclados, como como hojas inferiores, paneles laterales o deslizar para descartar.

Las APIs de Swipeable de Material dejaron de estar disponibles y se reemplazaron por la de Foundation AnchoredDraggable y se quitará en una versión futura. Esta guía se describe cómo migrar de las APIs de Swipeable a AnchoredDraggable.

Migra SwipeableState a AnchoredDraggableState

Comienza por identificar los cambios en tu contenedor de estado. AnchoredDraggableState de la cual no se puede heredar, y el desplazamiento se representa como Float.NaN antes de cuando se inicializa.

Actualiza tu contenedor de estado

AnchoredDraggableState es una clase final, lo que significa que no se puede heredar. de la imagen de la que se originó. Si tu componente existente se hereda de SwipeableState, actualiza tu contenedor de estado para que contenga una referencia a AnchoredDraggableState, en lugar de que heredan de ella:

Deslizable

class MySwitchState: SwipeableState()

Anclado arrastrable

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

Como tu contenedor de estado ya no hereda de SwipeableState, puedes quizás tengas que exponer APIs tú mismo. Las APIs más comunes que puedes usar son offset, progress, currentValue y targetValue.

Accede al desplazamiento

A diferencia de Swipeable, la offset de AnchoredDraggableState es Float.NaN antes cuando se inicializa. En AnchoredDraggable, los anclas se pueden pasar a constructor de AnchoredDraggableState o se actualiza mediante AnchoredDraggableState#updateAnchors Pasa los anclas a El constructor de AnchoredDraggableState inicializa el desplazamiento de inmediato.

Si tus anclas dependen del diseño o podrían cambiar, usa AnchoredDraggableState#updateAnchors para evitar volver a crear el estado cuando el elemento cambian las anclas.

Si usas updateAnchors, el desplazamiento será Float.NaN antes de pasar el se anclas a updateAnchors. Para no pasar accidentalmente Float.NaN a componentes, usa AnchoredDraggableState#requireOffset para que se se inicializó cuando se leyó. Esto te ayuda a detectar incoherencias o posibles errores desde el principio.

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

Migra Modifier.swipeable a Modifier.anchoredDraggable

Modifier.anchoredDraggable() reemplaza a Modifier.swipeable. Algunos de los parámetros de Modifier.swipeable() se movieron a AnchoredDraggableState directamente, como se describe en las siguientes secciones.

Define los anuncios fijos

Define los anclajes con el método del compilador DraggableAnchors. Luego, pasa a los archivos de AnchoredDraggableState#updateAnchors o AnchoredDraggableState constructor:

Constructor

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 los anclas son estáticas, pásalas al constructor. Si dependen de o no son estáticos, usa updateAnchors.

Define umbrales posicionales

El tipo y el nombre del parámetro de umbrales cambiaron. En lugar de tener un interfaz ThresholdConfig independiente, AnchoredDraggableState tiene una El parámetro positionalThreshold que toma una función lambda que muestra el del umbral. Por ejemplo, un umbral posicional del 50% podría ser expresada de la siguiente manera:

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

Un umbral posicional de 56dp se podría expresar de la siguiente manera:

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

Cómo definir los umbrales de velocidad

Los umbrales de velocidad también se pasan al constructor de AnchoredDraggableState. y también expresada como lambda:

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

Cambios en la plataforma de la API

Aquí tienes una descripción general de los cambios en la plataforma de la 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)

Se pasó al constructor AnchoredDraggableState como positionalThreshold

resistance: ResistanceConfig? = …

Aún no se admite. Consulta b/288084801 para conocer el estado más reciente.

velocityThreshold: Dp = 125.dp

Se pasó al constructor AnchoredDraggable.