Migrar de Swipeable para AnchoredDraggable

Swipeable é uma API Compose Material que ajuda a criar componentes que pode ser deslizado entre estados discretos, como páginas inferiores, gavetas ou deslizar para dispensar. Para oferecer um melhor suporte a casos de uso avançados, como âncoras que depender do tamanho de um componente, um sucessor foi publicado em Compose-Foundation 1.6.0-alpha01: AnchoredDraggable. AnchoredDraggable é uma API Foundation para a criação de componentes arrastáveis com estados ancorados, como como páginas inferiores, gavetas ou deslize para dispensar.

As APIs Swipeable do Material Design foram descontinuadas e substituídas pela API Foundation AnchoredDraggable e será removido em uma versão futura. Este guia descreve como migrar das APIs Swipeable para o AnchoredDraggable.

Migrar SwipeableState para AnchoredDraggableState

Comece identificando as mudanças no seu detentor de estado. AnchoredDraggableState não pode ser herdado, e o deslocamento é representado como Float.NaN antes é inicializado.

Atualizar o detentor de estado

AnchoredDraggableState é uma classe final, o que significa que ela não pode ser herdada se originou. Caso o componente atual seja herdado de SwipeableState, atualize o detentor do estado para manter uma referência ao AnchoredDraggableState em vez de herdando dele:

Deslizar

class MySwitchState: SwipeableState()

AnchoredDraggable

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

Como o detentor de estado não herda mais de SwipeableState, você talvez precise expor APIs por conta própria. As APIs mais comuns que você pode usar são offset, progress, currentValue e targetValue.

Acessar o deslocamento

Ao contrário de Swipeable, o offset da AnchoredDraggableState fica Float.NaN antes após a inicialização. Em AnchoredDraggable, as âncoras podem ser transmitidas para construtor de AnchoredDraggableState ou atualizado pela AnchoredDraggableState#updateAnchors. Passar as âncoras para O construtor de AnchoredDraggableState inicializa o deslocamento imediatamente.

Se seus anúncios âncora dependerem do layout ou puderem ser alterados, use AnchoredDraggableState#updateAnchors para evitar recriar o estado quando o as âncoras mudarem.

Se você usar updateAnchors, o deslocamento será Float.NaN antes de transmitir o âncoras ao updateAnchors. Para evitar transmitir Float.NaN acidentalmente ao componentes, use AnchoredDraggableState#requireOffset para exigir que os o deslocamento foi inicializado durante a leitura. Isso ajuda você a identificar inconsistências ou possíveis bugs logo no início.

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

Migrar Modifier.swipeable para Modifier.anchoredDraggable

Modifier.anchoredDraggable() substitui Modifier.swipeable. Algumas dos parâmetros de Modifier.swipeable() foram movidos para AnchoredDraggableState diretamente, conforme descrito nas seções a seguir.

Definir âncoras

Defina as âncoras usando o método do builder DraggableAnchors. Em seguida, transmita para AnchoredDraggableState#updateAnchors ou AnchoredDraggableState construtor:

Construtor

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 as âncoras forem estáticas, passe-as para o construtor. Se eles dependem ou não estáticos, use updateAnchors.

Definir limites de posicionamento

O tipo e o nome do parâmetro limites mudaram. Em vez de ter interface separada ThresholdConfig, AnchoredDraggableState tem um O parâmetro positionalThreshold que usa uma função lambda que retorna o do limite. Por exemplo, um limite de posicionamento de 50% pode ser expresso como:

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

Um limite posicional de 56dp pode ser expresso como:

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

Definir limites de velocidade

Os limites de velocidade também são transmitidos para o construtor do AnchoredDraggableState. e também expressa como uma lambda:

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

Mudanças na superfície da API

Confira abaixo uma visão geral das mudanças na plataforma da 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)

Passado para o construtor AnchoredDraggableState como positionalThreshold

resistance: ResistanceConfig? = …

Sem suporte no momento. Consulte b/288084801 para ver o status mais recente.

velocityThreshold: Dp = 125.dp

Passado para o construtor AnchoredDraggable