Swipeable
は Compose Material 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
から継承するのではなく、その参照を保持するように状態ホルダーを更新します。
スワイプ可能
class MySwitchState: SwipeableState()
アンカードラッグ可能
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) }
)
}
update アンカー
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
を使用します。
位置しきい値を定義する
しきい値パラメータのタイプと名前が変更されました。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 をご覧ください。 |
|
|