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ć palcem, np. arkusze dolne, panele lub elementy, które można zamknąć gestem. Aby lepiej obsługiwać zaawansowane przypadki użycia, takie jak kotwice, 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 u dołu ekranu, panele lub komponenty, które można zamknąć gestem przesuwania.

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

Przenoszenie 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 dziedziczyć po niej:

Możliwość przesuwania

class MySwitchState: SwipeableState()

AnchoredDraggable

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

Ponieważ klasa stanu nie dziedziczy już po klasie SwipeableState, być może będziesz musieć samodzielnie udostępniać interfejsy API. Najczęściej używane interfejsy API to offset, progress, currentValuetargetValue.

Dostęp do przesunięcia

W przeciwieństwie do Swipeable, AnchoredDraggableState's offset ma wartość Float.NaN przed zainicjowaniem. W AnchoredDraggable kotwice można przekazać do konstruktora AnchoredDraggableState lub zaktualizować za pomocą AnchoredDraggableState#updateAnchors. Przekazanie 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, 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ć, aby przesunięcie zostało zainicjowane podczas odczytu. 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) }
    }
}

Przenoszenie 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 sekcjach poniżej.

Definiowanie kotwic

Zdefiniuj kotwice 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

Zmieniono typ i nazwę parametru progów. 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 omówienie 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