Skip to content

Instantly share code, notes, and snippets.

@fvilarino
Created June 22, 2023 18:56
Show Gist options
  • Save fvilarino/ebb3ba8cd643246671ad5ea9b5476d8c to your computer and use it in GitHub Desktop.
Save fvilarino/ebb3ba8cd643246671ad5ea9b5476d8c to your computer and use it in GitHub Desktop.
Draggable Contente - Final
class MainActivity : ComponentActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContent {
PlaygroundTheme {
Surface(
modifier = Modifier.fillMaxSize(),
color = MaterialTheme.colorScheme.background,
) {
Box {
HorizontalDraggableSample(
modifier = Modifier
.fillMaxWidth()
.padding(top = 80.dp)
)
VerticalDraggableSample(
modifier = Modifier
.fillMaxHeight()
.align(Alignment.Center)
)
}
}
}
}
}
}
enum class DragAnchors(val fraction: Float) {
Start(0f),
OneQuarter(.25f),
Half(.5f),
ThreeQuarters(.75f),
End(1f),
}
@OptIn(ExperimentalFoundationApi::class)
@Composable
fun HorizontalDraggableSample(
modifier: Modifier = Modifier,
) {
val density = LocalDensity.current
val positionalThreshold = { distance: Float -> distance * 0.5f }
val velocityThreshold = { with(density) { 100.dp.toPx() } }
val animationSpec = tween<Float>()
val state = rememberSaveable(
density,
saver = AnchoredDraggableState.Saver(
animationSpec = animationSpec,
positionalThreshold = positionalThreshold,
velocityThreshold = velocityThreshold,
)
) {
AnchoredDraggableState(
initialValue = DragAnchors.Half,
positionalThreshold = positionalThreshold,
velocityThreshold = velocityThreshold,
animationSpec = animationSpec,
)
}
val contentSize = 80.dp
val contentSizePx = with(density) { contentSize.toPx() }
Box(
modifier
.onSizeChanged { layoutSize ->
val dragEndPoint = layoutSize.width - contentSizePx
state.updateAnchors(
DraggableAnchors {
DragAnchors
.values()
.filterNot { anchor -> anchor == DragAnchors.OneQuarter || anchor == DragAnchors.ThreeQuarters }
.forEach { anchor ->
anchor at dragEndPoint * anchor.fraction
}
}
)
}
) {
DraggableContent(
modifier = Modifier
.size(contentSize)
.offset {
IntOffset(
x = state.requireOffset().roundToInt(),
y = 0,
)
}
.anchoredDraggable(state, Orientation.Horizontal),
)
}
}
@OptIn(ExperimentalFoundationApi::class)
@Composable
fun VerticalDraggableSample(
modifier: Modifier = Modifier,
) {
val density = LocalDensity.current
val positionalThreshold = { distance: Float -> distance * 0.5f }
val velocityThreshold = { with(density) { 100.dp.toPx() } }
val animationSpec = tween<Float>()
val state = rememberSaveable(
density,
saver = AnchoredDraggableState.Saver(
animationSpec = animationSpec,
positionalThreshold = positionalThreshold,
velocityThreshold = velocityThreshold,
)
) {
AnchoredDraggableState(
initialValue = DragAnchors.Half,
positionalThreshold = positionalThreshold,
velocityThreshold = velocityThreshold,
animationSpec = animationSpec,
)
}
val contentSize = 80.dp
val contentSizePx = with(density) { contentSize.toPx() }
Box(
modifier
.onSizeChanged { layoutSize ->
val dragEndPoint = layoutSize.height - contentSizePx
state.updateAnchors(
DraggableAnchors {
DragAnchors
.values()
.forEach { anchor ->
anchor at dragEndPoint * anchor.fraction
}
}
)
}
) {
DraggableContent(
modifier = Modifier
.size(contentSize)
.offset {
IntOffset(
x = 0,
y = state.requireOffset().roundToInt(),
)
}
.anchoredDraggable(state, Orientation.Vertical),
)
}
}
@Composable
fun DraggableContent(
modifier: Modifier = Modifier,
) {
Image(
painter = painterResource(id = R.drawable.android_logo),
modifier = modifier,
contentDescription = null,
)
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment