Migracja z przesuwnego do AnchoredDraggable

Swipeable to interfejs API Compose Material, który ułatwia tworzenie komponentów, które można przełączać między stanami, takimi jak dolne arkusze, szuflady czy funkcja przesuwania w celu zamknięcia. Aby lepiej obsługiwać zaawansowane przypadki użycia, takie jak kotwy zależne od rozmiaru komponentu, opublikowaliśmy nową wersję Compose-Foundation 1.6.0-alpha01: AnchoredDraggable. AnchoredDraggable to interfejs Foundation API do tworzenia przeciąganych komponentów z zakotwiczonymi stanami, takich jak dolne panele, szuflady czy gest przesunięcia w bok, aby zamknąć.

Interfejsy API Material Swipeable zostały wycofane i zastąpione wersją AnchoredDraggable Foundation i zostaną usunięte w przyszłej wersji. Ten przewodnik opisuje, jak przejść z interfejsów API Swipeable na AnchoredDraggable.

Przenoszenie danych z SwipeableState do AnchoredDraggableState

Najpierw sprawdź, czy dane właściciela stanu uległy zmianie. Nie można dziedziczyć funkcji AnchoredDraggableState, a przed zainicjowaniem przesunięcie jest reprezentowane jako Float.NaN.

Zmień stan posiadacza

AnchoredDraggableState to klasa ostateczna, co oznacza, że nie można jej dziedziczyć. Jeśli istniejący komponent dziedziczy z poziomu SwipeableState, zamiast dziedziczenia z poziomu AnchoredDraggableState zaktualizuj element stanu, aby zawierał odwołanie do AnchoredDraggableState:

Przesuwne

class MySwitchState: SwipeableState()

AnchoredDraggable

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

Twój stan nie dziedziczy już z poziomu SwipeableState, więc musisz samodzielnie udostępnić interfejsy API. Najpopularniejsze interfejsy API, z których możesz korzystać, to offset, progress, currentValue i targetValue.

Dostęp do przesunięcia

W przeciwieństwie do Swipeable stan offset w AnchoredDraggableState ma wartość Float.NaN przed zainicjowaniem. W AnchoredDraggable reklamy zakotwiczone można przekazywać do konstruktora AnchoredDraggableState lub aktualizować za pomocą AnchoredDraggableState#updateAnchors. Przekazywanie kotwic do konstruktora AnchoredDraggableState powoduje natychmiastowe inicjowanie przesunięcia.

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

Jeśli użyjesz updateAnchors, przesunięcie będzie wynosić Float.NaN, zanim przekaziesz kotwy do updateAnchors. Aby uniknąć przypadkowego przekazania Float.NaN do komponentów, użyj wartości AnchoredDraggableState#requireOffset, aby wymagać inicjalizacji przesunięcia podczas odczytu. Pomoże Ci to w wczesnym wykrywaniu niespójności lub możliwych błędów.

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

Przenoszenie danych z Modifier.swipeable do Modifier.anchoredDraggable

Modifier.anchoredDraggable() zastępuje Modifier.swipeable. Niektóre parametry Modifier.swipeable() zostały przeniesione bezpośrednio do AnchoredDraggableState, jak opisano w następnych sekcjach.

Zdefiniuj kotwy

Określ kotwy za pomocą metody konstruktora DraggableAnchors. Następnie prześlij 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 funkcji updateAnchors.

Definiowanie progów pozycji

Zmieniono typ i nazwę parametru progi. Zamiast osobnego interfejsu ThresholdConfig funkcja AnchoredDraggableState ma parametr positionalThreshold, który przyjmuje funkcję lambda zwracającą pozycję progu. Na przykład próg pozycji 50% może być wyrażony w ten sposób:

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

Próg pozycyjny 56dp może być wyrażony w ten sposób:

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

Zdefiniuj progi prędkości

Próg prędkości jest też przekazywany do konstruktora AnchoredDraggableState, a także wyrażany jako 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)

Przekazana do konstruktora AnchoredDraggableState jako positionalThreshold

resistance: ResistanceConfig? = …

Jeszcze nieobsługiwane. Najnowsze informacje znajdziesz w problemie b/288084801.

velocityThreshold: Dp = 125.dp

Przekazano do konstruktora AnchoredDraggable