Migracja z przesuwnego do AnchoredDraggable

Swipeable to interfejs API Material Design, który ułatwia tworzenie komponentów, które można przesuwać między różnymi stanami, np. dolne arkusze, szuflady czy przeciąganie, aby zamknąć. Aby zapewnić lepszą obsługę zaawansowanych przypadków użycia, takich jak kotwice, które zależą od rozmiaru komponentu, opublikowano jego następcę w klasyfikacji Compose-Foundation 1.6.0-alpha01: AnchoredDraggable. AnchoredDraggable to interfejs API Podstawowy do tworzenia przeciąganych komponentów ze stanami zakotwiczonymi, np. dolne arkusze, szuflady czy „przesuń, aby zamknąć”.

Interfejsy API Swipeable materiału zostały wycofane i zastąpione przez interfejs AnchoredDraggable fundacji. W przyszłej wersji zostaną one usunięte. W tym przewodniku opisujemy, jak przejść z interfejsów API Swipeable na AnchoredDraggable.

Przenieś SwipeableState do AnchoredDraggableState

Zacznij od zidentyfikowania zmian na koncie właściciela stanu. Elementu AnchoredDraggableState nie można dziedziczyć, a przed jego zainicjowaniem przesunięcie jest przedstawione jako Float.NaN.

Zaktualizuj identyfikator stanu

AnchoredDraggableState jest klasą ostateczną, co oznacza, że nie można jej dziedziczyć. Jeśli istniejący komponent dziedziczy dane z elementu SwipeableState, zaktualizuj wartość atrybutu stan w taki sposób, by przechowywała odwołanie do elementu AnchoredDraggableState, zamiast z niego dziedziczyć:

Przesuwana

class MySwitchState: SwipeableState()

Zakotwiczony z możliwością przeciągania

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

Ponieważ Twój stan nie dziedziczy już z elementu SwipeableState, konieczne może być samodzielne udostępnienie interfejsów API. Najpopularniejsze interfejsy API, których możesz używać, to offset, progress, currentValue i targetValue.

Dostęp do przesunięcia

W przeciwieństwie do Swipeable zasada offset w AnchoredDraggableState ma wartość Float.NaN przed jej zainicjowaniem. W AnchoredDraggable kotwice można przekazywać do konstruktora AnchoredDraggableState lub aktualizować za pomocą AnchoredDraggableState#updateAnchors. Przekazywanie kotwic do konstruktora AnchoredDraggableState natychmiast inicjuje przesunięcie.

Jeśli kotwice zależą od układu lub mogą się zmienić, użyj AnchoredDraggableState#updateAnchors, aby uniknąć ponownego tworzenia stanu po zmianie tych kotwic.

Jeśli użyjesz metody updateAnchors, przesunięcie będzie wynosić Float.NaN przed przekazaniem kotwic do updateAnchors. Aby uniknąć przypadkowego przekazania atrybutu Float.NaN do komponentów, użyj funkcji AnchoredDraggableState#requireOffset, aby wymagać zainicjowania przesunięcia podczas jego odczytu. Pomaga to wychwytywać niespójności i możliwe błędy na wczesnym etapie.

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

Przenieś Modifier.swipeable do Modifier.anchoredDraggable

Modifier.anchoredDraggable() zastępuje Modifier.swipeable. Niektóre parametry parametru Modifier.swipeable() zostały przeniesione bezpośrednio do funkcji AnchoredDraggableState zgodnie z opisem w sekcjach poniżej.

Zdefiniuj reklamy zakotwiczone

Zdefiniuj kotwice za pomocą metody kreatora DraggableAnchors. Następnie przekaż je do konstruktora programu AnchoredDraggableState#updateAnchors lub AnchoredDraggableState:

Konstruktor

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

aktualizacje

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

Jeśli kotwice są statyczne, przekaż je do konstruktora. Użyj updateAnchors, jeśli zależy od układu lub nie jest statyczny.

Zdefiniuj progi pozycjonujące

Zmienił się typ i nazwa parametru progów. Zamiast osobnego interfejsu ThresholdConfig AnchoredDraggableState ma parametr positionalThreshold, który przyjmuje funkcję lambda, która zwraca pozycję progu. Na przykład próg pozycjonowania na poziomie 50% można zapisać w następujący sposób:

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

Próg pozycji w wysokości 56dp można wyrazić w następujący sposób:

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

Zdefiniuj progi prędkości

Progi prędkości są też przekazywane do konstruktora AnchoredDraggableState i wyrażone w postaci lambda:

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

Zmiany w interfejsie API

Poniżej znajdziesz przegląd zmian w interfejsie 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]

Nie dotyczy

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)

Przekazano do konstruktora AnchoredDraggableState jako positionalThreshold

resistance: ResistanceConfig? = …

Jeszcze nieobsługiwane. Ostatni stan możesz sprawdzić na stronie b/288084801.

velocityThreshold: Dp = 125.dp

Przekazano do konstruktora AnchoredDraggable