DraggableView.kt 3.0 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091
  1. package eu.mjdev.desktop.components.draggable
  2. import androidx.compose.desktop.ui.tooling.preview.Preview
  3. import androidx.compose.foundation.background
  4. import androidx.compose.foundation.gestures.detectDragGestures
  5. import androidx.compose.foundation.gestures.detectTapGestures
  6. import androidx.compose.foundation.layout.*
  7. import androidx.compose.runtime.Composable
  8. import androidx.compose.runtime.getValue
  9. import androidx.compose.runtime.setValue
  10. import androidx.compose.ui.Modifier
  11. import androidx.compose.ui.geometry.Offset
  12. import androidx.compose.ui.graphics.Color
  13. import androidx.compose.ui.graphics.graphicsLayer
  14. import androidx.compose.ui.input.pointer.pointerInput
  15. import androidx.compose.ui.unit.dp
  16. import androidx.compose.ui.zIndex
  17. import eu.mjdev.desktop.extensions.Compose.preview
  18. import eu.mjdev.desktop.extensions.Compose.rememberState
  19. import eu.mjdev.desktop.extensions.Modifier.conditional
  20. @Suppress("FunctionName")
  21. @Composable
  22. fun DraggableView(
  23. modifier: Modifier = Modifier,
  24. dragEnabled: Boolean = true,
  25. backgroundColor: Color = Color.Transparent,
  26. dragBackgroundColor: Color = Color.White.copy(alpha = 0.3f),
  27. contentPadding: PaddingValues = PaddingValues(0.dp),
  28. zIndex: Float = Float.MIN_VALUE,
  29. onDragStart: () -> Unit = {},
  30. onDragEnd: () -> Unit = {},
  31. onTap: () -> Unit = {},
  32. onDoubleTap: () -> Unit = {},
  33. onClick: () -> Unit = {},
  34. onContextMenuClick: () -> Unit = {},
  35. content: @Composable BoxScope.() -> Unit = {}
  36. ) {
  37. var position by rememberState(Offset.Zero)
  38. var isDragging by rememberState(false)
  39. Box(
  40. modifier = modifier.wrapContentSize()
  41. .conditional(zIndex > Float.MIN_VALUE) {
  42. zIndex(zIndex)
  43. }
  44. .graphicsLayer(
  45. translationX = position.x,
  46. translationY = position.y
  47. )
  48. .pointerInput(Unit) {
  49. detectTapGestures(
  50. onTap = { onTap() },
  51. onPress = { onClick() },
  52. onDoubleTap = { onDoubleTap() },
  53. onLongPress = { onContextMenuClick() }
  54. )
  55. }
  56. .pointerInput(Unit) {
  57. detectDragGestures(
  58. onDrag = { change, dragAmount ->
  59. if (dragEnabled) {
  60. change.consume()
  61. position += dragAmount
  62. }
  63. },
  64. onDragStart = {
  65. isDragging = true
  66. onDragStart()
  67. },
  68. onDragEnd = {
  69. isDragging = false
  70. onDragEnd()
  71. }
  72. )
  73. }.padding(contentPadding),
  74. content = {
  75. Box(
  76. modifier = Modifier
  77. .background(if (isDragging) dragBackgroundColor else backgroundColor)
  78. ) {
  79. content()
  80. }
  81. }
  82. )
  83. }
  84. @Preview
  85. @Composable
  86. fun DraggableViewPreview() = preview {
  87. DraggableView()
  88. }