از Swipeable به AnchoredDraggable مهاجرت کنید

Swipeable is a Compose Material API that helps you build components that can be swiped between discrete states, such as bottom sheets, drawers, or swipe-to-dismiss. To better support advanced use cases, such as anchors that depend on the size of a component, a successor was published in Compose-Foundation 1.6.0-alpha01: AnchoredDraggable . AnchoredDraggable is a Foundation API for building draggable components with anchored states, such as bottom sheets, drawers, or swipe-to-dismiss.

APIهای Swipeable متریال به نفع AnchoredDraggable بنیاد منسوخ شده‌اند و در نسخه‌های آینده حذف خواهند شد. این راهنما نحوه مهاجرت از APIهای Swipeable به AnchoredDraggable را شرح می‌دهد.

SwipeableState به AnchoredDraggableState منتقل کنید

با شناسایی تغییرات در نگهدارنده‌ی وضعیت (state holder) خود شروع کنید. AnchoredDraggableState نمی‌تواند از آن ارث‌بری کند، و offset قبل از مقداردهی اولیه به صورت Float.NaN نمایش داده می‌شود.

دارنده ایالت خود را به‌روزرسانی کنید

AnchoredDraggableState یک کلاس final است، به این معنی که نمی‌توان از آن ارث‌بری کرد. اگر کامپوننت موجود شما از SwipeableState ارث‌بری می‌کند، نگهدارنده‌ی وضعیت خود را به‌روزرسانی کنید تا به جای ارث‌بری از AnchoredDraggableState ارجاعی به آن را در خود نگه دارد:

قابل کشیدن انگشت

class MySwitchState: SwipeableState()

قابل کشیدن و رها کردن

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

از آنجایی که دارنده وضعیت شما دیگر از SwipeableState ارث‌بری نمی‌کند، ممکن است مجبور شوید خودتان APIها را در معرض نمایش قرار دهید. رایج‌ترین APIهایی که می‌توانید استفاده کنید offset ، progress ، currentValue و targetValue هستند.

دسترسی به آفست

برخلاف Swipeable ، offset مربوط به AnchoredDraggableState قبل از مقداردهی اولیه، Float.NaN است. در AnchoredDraggable ، می‌توان anchorها را به سازنده‌ی AnchoredDraggableState ارسال کرد یا از طریق AnchoredDraggableState#updateAnchors آن‌ها را به‌روزرسانی کرد. ارسال anchorها به سازنده‌ی AnchoredDraggableState ، offset را بلافاصله مقداردهی اولیه می‌کند.

اگر لنگرهای شما به طرح‌بندی بستگی دارند یا ممکن است تغییر کنند، AnchoredDraggableState#updateAnchors استفاده کنید تا از ایجاد مجدد حالت هنگام تغییر لنگرها جلوگیری شود.

اگر از updateAnchors استفاده می‌کنید، قبل از ارسال anchorها به updateAnchors ، offset برابر Float.NaN خواهد بود. برای جلوگیری از ارسال تصادفی Float.NaN به کامپوننت‌ها، AnchoredDraggableState#requireOffset استفاده کنید تا هنگام خواندن offset، مقداردهی اولیه آن الزامی شود. این به شما کمک می‌کند تا ناسازگاری‌ها یا اشکالات احتمالی را در مراحل اولیه تشخیص دهید.

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

انتقال Modifier.swipeable به Modifier.anchoredDraggable

Modifier.anchoredDraggable() جایگزین Modifier.swipeable می‌شود. برخی از پارامترهای Modifier.swipeable() مستقیماً به AnchoredDraggableState منتقل شده‌اند، همانطور که در بخش‌های بعدی توضیح داده شده است.

تعریف لنگرها

لنگرها را با استفاده از متد سازنده‌ی DraggableAnchors تعریف کنید. سپس، آنها را به AnchoredDraggableState#updateAnchors یا سازنده‌ی AnchoredDraggableState ارسال کنید:

سازنده

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

به‌روزرسانی لنگرها

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

اگر anchorها ایستا هستند، آنها را به سازنده (constructor) منتقل کنید. اگر به layout وابسته هستند یا ایستا نیستند، از updateAnchors استفاده کنید.

تعریف آستانه‌های موقعیتی

نوع و نام پارامتر thresholds تغییر کرده است. به جای داشتن یک رابط ThresholdConfig جداگانه، AnchoredDraggableState یک پارامتر positionalThreshold دارد که یک تابع lambda می‌گیرد که موقعیت آستانه را برمی‌گرداند. برای مثال، یک آستانه موقعیتی ۵۰٪ می‌تواند به صورت زیر بیان شود:

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

یک آستانه موقعیتی 56dp را می‌توان به صورت زیر بیان کرد:

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

تعریف آستانه‌های سرعت

آستانه‌های سرعت نیز به سازنده‌ی AnchoredDraggableState ارسال می‌شوند و به صورت یک لامبدا نیز بیان می‌شوند:

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

تغییرات در سطح API

نمای کلی از تغییرات سطح 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 ]

ناموجود

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)

به عنوان positionalThreshold به سازنده‌ی AnchoredDraggableState ارسال شد.

resistance: ResistanceConfig? = …

هنوز پشتیبانی نمی‌شود. برای اطلاع از آخرین وضعیت به b/288084801 مراجعه کنید.

velocityThreshold: Dp = 125.dp

به سازنده‌ی AnchoredDraggable ارسال شد