Swipeable
は、ボトムシート、ドロワー、スワイプして閉じるなど、個別の状態をスワイプできるコンポーネントの作成に役立つ Compose マテリアル API です。コンポーネントのサイズに依存するアンカーなど、高度なユースケースをより適切にサポートするために、Compose-Foundation 1.6.0-alpha01 で後継となる AnchoredDraggable
が公開されました。AnchoredDraggable
は、アンカー状態のドラッグ可能なコンポーネント(ボトムシート、引き出し、スワイプして閉じるなど)を構築するための Foundation API です。
マテリアルの Swipeable
API は非推奨になり、Foundation の AnchoredDraggable
に置き換えられました。今後のリリースで削除される予定です。このガイドでは、Swipeable
API から AnchoredDraggable
に移行する方法について説明します。
SwipeableState
を AnchoredDraggableState
に移行する
まず、状態ホルダーの変更を特定します。AnchoredDraggableState
は継承できません。オフセットは初期化前に Float.NaN
として表されます。
状態ホルダーを更新する
AnchoredDraggableState
は最終クラスです。つまり、継承できません。既存のコンポーネントが SwipeableState
から継承している場合は、状態保持クラスを更新して、AnchoredDraggableState
から継承するのではなく、AnchoredDraggableState
への参照を保持するようにします。
スワイプ可能
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
を使用して、読み取り時にオフセットが初期化されていることを要求します。これにより、不整合や潜在的なバグを早期に発見できます。
@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.swipeable
に代わり Modifier.anchoredDraggable()
になりました。次のセクションで説明するように、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
を使用します。
位置のしきい値を定義する
thresholds パラメータの型と名前が変更されました。AnchoredDraggableState
には、個別の ThresholdConfig
インターフェースではなく、しきい値の位置を返すラムダ関数を受け取る positionalThreshold
パラメータがあります。たとえば、50% の位置基準は次のように表すことができます。
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
|
|
---|---|
|
|
|
|
|
|
|
|
|
|
|
なし |
|
|
|
|
|
|
|
|
|
|
|
Modifier.anchoredDraggable
|
|
---|---|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
現時点ではサポートされていません。最新のステータスについては、b/288084801 をご覧ください。 |
|
|