Swipeable 是一个 Compose Material API,可帮助您构建可在离散状态之间滑动的组件,例如底部动作条、抽屉式导航栏或滑动关闭。为了更好地支持高级用例(例如依赖于组件大小的锚点),我们在 Compose-Foundation 1.6.0-alpha01 中发布了一个后续版本:AnchoredDraggable。AnchoredDraggable
是一个 Foundation API,用于构建具有锚定状态的可拖动组件,例如底部动作条、抽屉式导航栏或滑动关闭。
Material 的 Swipeable API 已被弃用,取而代之的是 Foundation 的 AnchoredDraggable,并且将在未来的版本中移除。本指南介绍了如何从 Swipeable API 迁移到 AnchoredDraggable。
将 SwipeableState 迁移到 AnchoredDraggableState
首先,确定状态容器的更改。AnchoredDraggableState
无法继承,并且在初始化之前,偏移量表示为 Float.NaN。
更新状态容器
AnchoredDraggableState 是一个最终类,这意味着它无法继承。如果现有组件继承自 SwipeableState,请更新状态容器以持有对 AnchoredDraggableState 的引用,而不是继承自它:
Swipeable
class MySwitchState: SwipeableState()
AnchoredDraggable
class MySwitchState {
private val anchoredDraggableState = AnchoredDraggableState(...)
}
由于状态容器不再继承自 SwipeableState,因此您可能需要自行公开 API。您可以使用的最常见 API 是
offset、progress、currentValue 和 targetValue。
访问偏移量
与 Swipeable 不同,AnchoredDraggableState 的 offset 在初始化之前为 Float.NaN。在 AnchoredDraggable 中,锚点可以传递给
AnchoredDraggableState 的构造函数,也可以通过
AnchoredDraggableState#updateAnchors 进行更新。将锚点传递给 AnchoredDraggableState 的构造函数会立即初始化偏移量。
如果锚点依赖于布局或可能会发生变化,请使用 AnchoredDraggableState#updateAnchors,以避免在锚点发生变化时重新创建状态。
如果您使用 updateAnchors,则在将锚点传递给 updateAnchors 之前,偏移量将为 Float.NaN。为避免意外地将 Float.NaN 传递给
组件,请使用 AnchoredDraggableState#requireOffset 要求在
读取偏移量时必须已对其进行初始化。这有助于您尽早发现不一致或可能的 bug。
@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) }
)
}
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) }
)
}
如果锚点是静态的,请将其传递给构造函数。如果锚点依赖于布局或不是静态的,请使用 updateAnchors。
定义位置阈值
阈值参数的类型和名称已发生变化。没有单独的ThresholdConfig接口,AnchoredDraggableState具有一个
positionalThreshold参数,该参数接受一个 lambda 函数,该函数返回阈值的位置。例如,50% 的位置阈值可以表示为:
val anchoredDraggableState = AnchoredDraggableState(
positionalThreshold = { distance -> distance * 0.5f },
...
)
56dp 的位置阈值可以表示为:
val density = LocalDensity.current
val anchoredDraggableState = AnchoredDraggableState(
positionalThreshold = { with(density) { 56.dp.toPx() } },
...
)
定义速度阈值
速度阈值也会传递给 AnchoredDraggableState 的构造函数,并且也会表示为 lambda:
val density = LocalDensity.current
val anchoredDraggableState = AnchoredDraggableState(
velocityThreshold = { with(density) { 125.dp.toPx() } },
...
)
API 外观的更改
如需大致了解 API 外观的更改,请参阅下文。
AnchoredDraggableState
|
|
|---|---|
|
|
|
|
|
|
|
|
|
|
|
不适用 |
|
|
|
|
|
|
|
|
|
|
|
Modifier.anchoredDraggable
|
|
|---|---|
|
|
|
|
|
|
|
|
|
|
|
|
|
作为 |
|
暂不支持。如需了解最新状态,请参阅 b/288084801。 |
|
传递给 |