Migracja z przesuwnego do AnchoredDraggable

Swipeable to interfejs API Compose Material, który pomaga tworzyć komponenty, między których dyskretnymi stanami można przesuwać, np. arkusze dolne, panele lub komponenty z funkcją przesuwania w celu zamknięcia. Aby lepiej obsługiwać zaawansowane przypadki użycia, takie jak elementy zakotwiczone, które zależą od rozmiaru komponentu, w Compose-Foundation 1.6.0-alpha01 opublikowano następcę: AnchoredDraggable. AnchoredDraggable to podstawowy interfejs API do tworzenia komponentów, które można przeciągać i które mają stany zakotwiczone, np. arkusze dolne, panele lub funkcje zamykania przez przesunięcie.

Interfejsy API Swipeable Material zostały wycofane na rzecz interfejsów AnchoredDraggable Foundation i w przyszłej wersji zostaną usunięte. Z tego przewodnika dowiesz się, jak przejść z interfejsów API Swipeable na AnchoredDraggable.

Przenieś SwipeableState do AnchoredDraggableState

Zacznij od zidentyfikowania zmian w zmiennej stanu. AnchoredDraggableState nie może być dziedziczony, a przesunięcie jest reprezentowane jako Float.NaN przed zainicjowaniem.

Aktualizowanie zmiennej stanu

AnchoredDraggableState to klasa ostateczna, co oznacza, że nie można jej dziedziczyć. Jeśli istniejący komponent dziedziczy po SwipeableState, zaktualizuj zmienną stanu, aby przechowywała odwołanie do AnchoredDraggableState zamiast po niej dziedziczyć:

Przesuwane

class MySwitchState: SwipeableState()

AnchoredDraggable

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

Ponieważ klasa stanu nie dziedziczy już z klasy SwipeableState, być może będziesz musiał(-a) samodzielnie udostępniać interfejsy API. Najczęściej używane interfejsy API to offset, progress, currentValue i targetValue.

Dostęp do przesunięcia

W przeciwieństwie do Swipeable, AnchoredDraggableState ma wartość offset równą Float.NaN przed zainicjowaniem. W AnchoredDraggable kotwice można przekazać do konstruktora AnchoredDraggableState lub zaktualizować za pomocą AnchoredDraggableState#updateAnchors. Przekazanie punktów zakotwiczenia 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, gdy kotwice się zmienią.

Jeśli użyjesz updateAnchors, przesunięcie wyniesie Float.NaN przed przekazaniem kotwic do updateAnchors. Aby uniknąć przypadkowego przekazania wartości Float.NaN do komponentów, użyj AnchoredDraggableState#requireOffset, aby wymagać zainicjowania przesunięcia podczas jego odczytywania. Pomoże Ci to wcześnie wykryć niespójności lub możliwe błędy.

@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 usługi Modifier.swipeable() zostały przeniesione bezpośrednio do usługi AnchoredDraggableState, jak opisano w sekcjach poniżej.

Definiowanie kotwic

Zdefiniuj punkty zakotwiczenia za pomocą metody DraggableAnchors. Następnie przekaż je do konstruktora 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) }
    )
}

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

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

Określanie progów pozycji

Zmienił się typ i nazwa parametru thresholds. Zamiast osobnego interfejsu ThresholdConfig funkcja AnchoredDraggableState ma parametr positionalThreshold, który przyjmuje funkcję lambda zwracającą pozycję progu. Na przykład próg pozycji wynoszący 50% można wyrazić w ten sposób:

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

Próg pozycji 56dp można wyrazić w ten sposób:

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

Określanie progów prędkości

Progi prędkości są też przekazywane do konstruktora AnchoredDraggableState i wyrażane jako lambda:

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

Zmiany w zestawie interfejsów 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? = …

Opcja jeszcze nieobsługiwana. Najnowsze informacje znajdziesz na stronie b/288084801.

velocityThreshold: Dp = 125.dp

Przekazano do konstruktora AnchoredDraggable