mirror of
https://github.com/AllanWang/Frost-for-Facebook.git
synced 2024-11-08 12:02:33 +01:00
Convert drag target to modifier only
This commit is contained in:
parent
bdb7fa6aa8
commit
7eae53c78a
@ -37,6 +37,11 @@ import com.pitchedapps.frost.ext.toIntOffset
|
||||
* https://blog.canopas.com/android-drag-and-drop-ui-element-in-jetpack-compose-14922073b3f1
|
||||
*/
|
||||
|
||||
/**
|
||||
* Container for drag interactions.
|
||||
*
|
||||
* This must hold all drag and drop targets.
|
||||
*/
|
||||
@Composable
|
||||
fun <T> DragContainer(
|
||||
modifier: Modifier = Modifier,
|
||||
@ -51,38 +56,12 @@ fun <T> DragContainer(
|
||||
}
|
||||
|
||||
/**
|
||||
* Drag target.
|
||||
* Drag target modifier.
|
||||
*
|
||||
* The [content] composable may be composed where [DragTarget] is defined, or in [DraggingContents]
|
||||
* depending on drag state. Keep this in mind based on the isDragging flag.
|
||||
*
|
||||
* [key] is used to distinguish between multiple dragging targets. If only one should be used at a
|
||||
* time, this can be the same key. If there is a key conflict, only the first target will be
|
||||
* dragged.
|
||||
* This should be applied to the composable that will be dragged. The modifier will capture
|
||||
* positions and hide (alpha 0) the target when dragging.
|
||||
*/
|
||||
@Composable
|
||||
fun <T> DragTarget(
|
||||
key: String = "",
|
||||
data: T,
|
||||
draggableState: DraggableState<T>,
|
||||
content: DraggableComposeContent,
|
||||
) {
|
||||
|
||||
val dragTargetState =
|
||||
draggableState.rememberDragTarget(
|
||||
key = key,
|
||||
data = data,
|
||||
content = content,
|
||||
)
|
||||
|
||||
Box(
|
||||
modifier = Modifier.dragTarget(dragTargetState),
|
||||
) {
|
||||
content(isDragging = false)
|
||||
}
|
||||
}
|
||||
|
||||
private fun <T> Modifier.dragTarget(dragTargetState: DragTargetState<T>): Modifier {
|
||||
fun <T> Modifier.dragTarget(dragTargetState: DragTargetState<T>): Modifier {
|
||||
return onGloballyPositioned {
|
||||
dragTargetState.windowPosition = it.positionInWindow()
|
||||
dragTargetState.size = it.size
|
||||
@ -112,13 +91,19 @@ private fun <T> Modifier.dragTarget(dragTargetState: DragTargetState<T>): Modifi
|
||||
draggableState.onDragEnd(key)
|
||||
dragTargetState.isDragging = false
|
||||
}
|
||||
}
|
||||
},
|
||||
)
|
||||
}
|
||||
// We still need to draw to track size changes
|
||||
.alpha(if (dragTargetState.isDragging) 0f else 1f)
|
||||
}
|
||||
|
||||
/**
|
||||
* Drop target modifier.
|
||||
*
|
||||
* This should be applied to targets that capture drag targets. The modifier will listen to
|
||||
* composable bounds.
|
||||
*/
|
||||
fun <T> Modifier.dropTarget(dropTargetState: DropTargetState<T>): Modifier {
|
||||
return onGloballyPositioned { dropTargetState.bounds = it.boundsInWindow() }
|
||||
}
|
||||
@ -146,6 +131,6 @@ private fun <T> DraggingContent(target: DragTargetState<T>) {
|
||||
modifier =
|
||||
Modifier.size(target.size.toDpSize(density)).offset { target.dragPosition.toIntOffset() },
|
||||
) {
|
||||
target.composable(true)
|
||||
target.dragComposable()
|
||||
}
|
||||
}
|
||||
|
@ -27,8 +27,6 @@ import androidx.compose.ui.geometry.Offset
|
||||
import androidx.compose.ui.geometry.Rect
|
||||
import androidx.compose.ui.unit.IntSize
|
||||
|
||||
typealias DraggableComposeContent = @Composable (isDragging: Boolean) -> Unit
|
||||
|
||||
fun interface OnDrop<T> {
|
||||
fun onDrop(dragTarget: String, dragData: T, dropTarget: String)
|
||||
}
|
||||
@ -57,7 +55,7 @@ interface DraggableState<T> {
|
||||
fun onDragEnd(key: String)
|
||||
|
||||
@Composable
|
||||
fun rememberDragTarget(key: String, data: T, content: DraggableComposeContent): DragTargetState<T>
|
||||
fun rememberDragTarget(key: String, data: T, content: @Composable () -> Unit): DragTargetState<T>
|
||||
|
||||
@Composable fun rememberDropTarget(key: String): DropTargetState<T>
|
||||
}
|
||||
@ -101,11 +99,11 @@ class DraggableStateImpl<T>(private val onDrop: OnDrop<T>) : DraggableState<T> {
|
||||
override fun rememberDragTarget(
|
||||
key: String,
|
||||
data: T,
|
||||
content: DraggableComposeContent,
|
||||
content: @Composable () -> Unit,
|
||||
): DragTargetState<T> {
|
||||
val target =
|
||||
remember(key, data, content, this) {
|
||||
DragTargetState(key = key, data = data, draggableState = this, composable = content)
|
||||
DragTargetState(key = key, data = data, draggableState = this, dragComposable = content)
|
||||
}
|
||||
DisposableEffect(target) { onDispose { activeDragTargets.remove(key) } }
|
||||
return target
|
||||
@ -174,7 +172,7 @@ class DragTargetState<T>(
|
||||
val key: String,
|
||||
val data: T,
|
||||
val draggableState: DraggableStateImpl<T>,
|
||||
val composable: DraggableComposeContent,
|
||||
val dragComposable: @Composable () -> Unit,
|
||||
) {
|
||||
var isDragging by mutableStateOf(false)
|
||||
var windowPosition = Offset.Zero
|
||||
|
@ -60,8 +60,8 @@ import androidx.compose.ui.text.style.TextAlign
|
||||
import androidx.compose.ui.text.style.TextOverflow
|
||||
import androidx.compose.ui.unit.dp
|
||||
import com.pitchedapps.frost.compose.draggable.DragContainer
|
||||
import com.pitchedapps.frost.compose.draggable.DragTarget
|
||||
import com.pitchedapps.frost.compose.draggable.DraggableState
|
||||
import com.pitchedapps.frost.compose.draggable.dragTarget
|
||||
import com.pitchedapps.frost.compose.draggable.dropTarget
|
||||
import com.pitchedapps.frost.compose.draggable.rememberDraggableState
|
||||
import com.pitchedapps.frost.compose.effects.rememberShakeState
|
||||
@ -116,22 +116,19 @@ fun TabSelector(
|
||||
columns = GridCells.Fixed(4),
|
||||
) {
|
||||
items(unselected, key = { it.key }) { data ->
|
||||
DragTarget(key = data.key, data = data, draggableState = draggableState) { isDragging ->
|
||||
if (isDragging) {
|
||||
// In dragging box
|
||||
val dragTargetState =
|
||||
draggableState.rememberDragTarget(key = data.key, data = data) {
|
||||
DraggingTabItem(data = data)
|
||||
} else {
|
||||
// In LazyVerticalGrid
|
||||
|
||||
val shakeState = rememberShakeState()
|
||||
|
||||
TabItem(
|
||||
modifier = Modifier.animateItemPlacement().shake(shakeState),
|
||||
data = data,
|
||||
onClick = { shakeState.shake() },
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
val shakeState = rememberShakeState()
|
||||
|
||||
TabItem(
|
||||
modifier =
|
||||
Modifier.animateItemPlacement().dragTarget(dragTargetState).shake(shakeState),
|
||||
data = data,
|
||||
onClick = { shakeState.shake() },
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user