Di chuyển từ Swipeable sang AnchoredDraggable

Swipeable là một API Compose Material giúp bạn tạo các thành phần bạn có thể vuốt giữa các trạng thái riêng biệt, chẳng hạn như bảng dưới cùng, ngăn hoặc vuốt để đóng. Để hỗ trợ tốt hơn cho các trường hợp sử dụng nâng cao, chẳng hạn như quảng cáo cố định phụ thuộc vào kích thước của một thành phần, một thành phần kế thừa được xuất bản trong Compose-Foundation 1.6.0-alpha01: AnchoredDraggable. AnchoredDraggable là một API nền tảng để tạo các thành phần có thể kéo với các trạng thái cố định, chẳng hạn như dưới dạng bảng dưới cùng, ngăn hoặc thao tác vuốt để đóng.

Ngừng sử dụng các API Swipeable của Material và thay bằng API của Foundation AnchoredDraggable và sẽ bị xoá trong bản phát hành sau này. Hướng dẫn này mô tả cách di chuyển từ API Swipeable sang AnchoredDraggable.

Di chuyển SwipeableState sang AnchoredDraggableState

Bắt đầu bằng cách xác định các thay đổi đối với phần tử giữ trạng thái. AnchoredDraggableState không thể kế thừa từ, và độ lệch được biểu thị là Float.NaN trước đã được khởi tạo.

Cập nhật phần tử giữ trạng thái

AnchoredDraggableState là lớp cuối cùng, có nghĩa là không thể kế thừa lớp này . Nếu thành phần hiện có của bạn kế thừa từ SwipeableState, hãy cập nhật phần tử giữ trạng thái để giữ tham chiếu đến AnchoredDraggableState thay vì việc kế thừa từ dữ liệu đó:

Có thể vuốt

class MySwitchState: SwipeableState()

AnchoredKéogable

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

Vì phần tử giữ trạng thái không kế thừa từ SwipeableState nữa, bạn có thể phải tự hiển thị API. Các API phổ biến nhất mà bạn có thể sử dụng là offset, progress, currentValuetargetValue.

Truy cập vào giá trị bù trừ

Không giống như trong Swipeable, offset của AnchoredDraggableStateFloat.NaN trước thì sẽ được khởi tạo. Trong AnchoredDraggable, các quảng cáo cố định có thể được chuyển đến Hàm khởi tạo của AnchoredDraggableState hoặc được cập nhật thông qua AnchoredDraggableState#updateAnchors. Chuyển quảng cáo cố định đến Hàm khởi tạo của AnchoredDraggableState sẽ khởi tạo độ lệch ngay lập tức.

Nếu quảng cáo cố định phụ thuộc vào bố cục hoặc có thể thay đổi, hãy sử dụng AnchoredDraggableState#updateAnchors để tránh tạo lại trạng thái khi quảng cáo cố định.

Nếu bạn sử dụng updateAnchors, độ lệch sẽ là Float.NaN trước khi truyền quảng cáo cố định cuối màn hình vào updateAnchors. Để tránh vô tình truyền Float.NaN đến hãy sử dụng AnchoredDraggableState#requireOffset để yêu cầu thuộc tính được khởi tạo khi đọc. Điều này giúp bạn nắm bắt sự không thống nhất hoặc lỗi có thể xảy ra ở giai đoạn đầu.

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

Di chuyển Modifier.swipeable sang Modifier.anchoredDraggable

Modifier.anchoredDraggable() thay thế Modifier.swipeable. Hơi nhiều trong số các thông số của Modifier.swipeable() đã chuyển sang AnchoredDraggableState như được mô tả trong các phần sau đây.

Xác định quảng cáo cố định

Xác định các neo bằng phương thức tạo DraggableAnchors. Sau đó, truyền chúng vào nhóm AnchoredDraggableState#updateAnchors hoặc AnchoredDraggableState hàm khởi tạo:

Hàm dựng

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

Nếu các neo ở dạng tĩnh, hãy truyền các neo này vào hàm khởi tạo. Nếu chúng phụ thuộc vào hoặc không tĩnh, hãy sử dụng updateAnchors.

Xác định ngưỡng vị trí

Loại và tên của thông số ngưỡng đã thay đổi. Thay vì có một giao diện ThresholdConfig riêng biệt, AnchoredDraggableState có một Tham số positionalThreshold nhận hàm lambda trả về giá trị vị trí của ngưỡng. Ví dụ: ngưỡng vị trí là 50% có thể là được biểu thị dưới dạng:

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

Ngưỡng vị trí của 56dp có thể được biểu thị như sau:

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

Xác định ngưỡng vận tốc

Các ngưỡng tốc độ cũng được truyền đến hàm khởi tạo của AnchoredDraggableState, và cũng được biểu thị dưới dạng lambda:

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

Các thay đổi đối với nền tảng API

Xem thông tin tổng quan về những thay đổi đối với nền tảng API ở bên dưới.

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]

Không có thời gian

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)

Đã truyền đến hàm khởi tạo AnchoredDraggableState dưới dạng positionalThreshold

resistance: ResistanceConfig? = …

Chưa được hỗ trợ. Hãy xem b/288084801 để biết trạng thái mới nhất.

velocityThreshold: Dp = 125.dp

Đã truyền đến hàm khởi tạo AnchoredDraggable