Last active
February 3, 2021 18:17
-
-
Save loloof64/048014437131a3b21acdf5b206d25908 to your computer and use it in GitHub Desktop.
Jetpack compose alpha11 Drag and Drop in a strange checker board
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import androidx.compose.foundation.Canvas | |
import androidx.compose.foundation.background | |
import androidx.compose.foundation.layout.size | |
import androidx.compose.runtime.Composable | |
import androidx.compose.runtime.getValue | |
import androidx.compose.runtime.setValue | |
import androidx.compose.runtime.mutableStateOf | |
import androidx.compose.runtime.remember | |
import androidx.compose.ui.Modifier | |
import androidx.compose.ui.geometry.Offset | |
import androidx.compose.ui.geometry.Size | |
import androidx.compose.ui.gesture.DragObserver | |
import androidx.compose.ui.gesture.dragGestureFilter | |
import androidx.compose.ui.graphics.Color | |
import androidx.compose.ui.graphics.drawscope.DrawScope | |
import androidx.compose.ui.platform.AmbientDensity | |
import androidx.compose.ui.tooling.preview.Preview | |
import androidx.compose.ui.unit.Dp | |
import androidx.compose.ui.unit.dp | |
import kotlin.math.floor | |
import android.graphics.Color as LegacyColor | |
class PiecesValues(initial: Array<Array<String?>>) { | |
private var internalValues = initial | |
fun getValueAt(row: Int, col: Int): String? { | |
return internalValues[row][col] | |
} | |
fun getColorAt(row: Int, col: Int): Color? { | |
return internalValues[row][col]?.let { | |
getColor(it) | |
} | |
} | |
fun setValueAt(row: Int, col: Int, value: String?) { | |
internalValues[row][col] = value | |
} | |
private fun getColor(colorString: String): Color { | |
return Color(LegacyColor.parseColor("#$colorString")) | |
} | |
} | |
@Composable | |
fun ItemsGrid(sizePx: Float, modifier: Modifier = Modifier) { | |
fun Float.getCoordFromAbsolute() : Int { | |
return floor((this - sizePx * 0.055f) / (sizePx * 0.11f)).toInt() | |
} | |
var dndStartX by remember { mutableStateOf(Float.NEGATIVE_INFINITY) } | |
var dndStartY by remember { mutableStateOf(Float.NEGATIVE_INFINITY) } | |
var dndDestX by remember { mutableStateOf(Float.NEGATIVE_INFINITY) } | |
var dndDestY by remember { mutableStateOf(Float.NEGATIVE_INFINITY) } | |
var values by remember { | |
mutableStateOf( | |
PiecesValues( | |
arrayOf( | |
arrayOf("DCBA23", "123456", null, "CB23DE", null, null, "45C38F", null), | |
arrayOf(null, null, null, "56E3DF", null, null, "45ED2C", null), | |
arrayOf(null, null, null, "CB23DE", null, null, null, null), | |
arrayOf("125687", null, null, null, null, null, null, null), | |
arrayOf(null, "89DC2F", null, null, null, null, null, null), | |
arrayOf(null, "123456", null, null, null, null, "DF52C9", null), | |
arrayOf(null, null, null, null, null, "ABCDEF", null, null), | |
arrayOf(null, "CAFEBABE", null, null, null, null, null, null), | |
) | |
) | |
) | |
} | |
val sizeDp = with(AmbientDensity.current) { | |
sizePx.toDp() | |
} | |
return Canvas( | |
modifier = modifier | |
.size(sizeDp) | |
.background(Color(LegacyColor.RED)) | |
.dragGestureFilter( | |
dragObserver = object : DragObserver { | |
override fun onStart(downPosition: Offset) { | |
val selectedCol = | |
downPosition.x.getCoordFromAbsolute() | |
if (selectedCol < 0 || selectedCol > 7) return | |
val selectedRow = | |
downPosition.y.getCoordFromAbsolute() | |
if (selectedRow < 0 || selectedRow > 7) return | |
values.getColorAt(row = selectedRow, col = selectedCol) ?: return | |
dndStartX = downPosition.x | |
dndStartY = downPosition.y | |
dndDestX = downPosition.x | |
dndDestY = downPosition.y | |
} | |
override fun onDrag(dragDistance: Offset): Offset { | |
dndDestX += dragDistance.x | |
dndDestY += dragDistance.y | |
return dragDistance | |
} | |
override fun onStop(velocity: Offset) { | |
val startCol = dndStartX.getCoordFromAbsolute() | |
val startRow = dndStartY.getCoordFromAbsolute() | |
val endCol = dndDestX.getCoordFromAbsolute() | |
val endRow = dndDestY.getCoordFromAbsolute() | |
if (endCol < 0 || endCol > 7 || endRow < 0 || endRow > 7) { | |
onCancel() | |
return | |
} | |
val startCellValue = values.getValueAt(col = startCol, row = startRow) | |
values.setValueAt(col = startCol, row = startRow, value = null) | |
values.setValueAt(col = endCol, row = endRow, value = startCellValue) | |
onCancel() | |
} | |
override fun onCancel() { | |
dndStartX = Float.NEGATIVE_INFINITY | |
dndStartY = Float.NEGATIVE_INFINITY | |
dndDestX = Float.NEGATIVE_INFINITY | |
dndDestY = Float.NEGATIVE_INFINITY | |
} | |
}, | |
startDragImmediately = true, | |
) | |
) { | |
val startCol = dndStartX.getCoordFromAbsolute() | |
val startRow = dndStartY.getCoordFromAbsolute() | |
val selectedCol = dndDestX.getCoordFromAbsolute() | |
val selectedRow = dndDestY.getCoordFromAbsolute() | |
(0 until 8).forEach { row -> | |
(0 until 8).forEach { col -> | |
val isDndStartCell = startCol == col && startRow == row | |
val isDndDestCell = selectedCol == col && selectedRow == row | |
val isDndCrossCell = selectedCol == col || selectedRow == row | |
val whiteCell = (row + col) % 2 == 0 | |
var color = if (whiteCell) Color(LegacyColor.WHITE) else Color(LegacyColor.BLACK) | |
if (isDndStartCell) color = Color(LegacyColor.RED) | |
if (isDndCrossCell) color = Color(LegacyColor.MAGENTA) | |
if (isDndDestCell) color = Color(LegacyColor.GREEN) | |
drawCell(size = sizeDp / 9, row = row, col = col, color = color) | |
values.getColorAt(row, col)?.let { | |
val isTheDraggedPiece = startCol == col && startRow == row | |
val x = if (isTheDraggedPiece) dndDestX else sizePx * 0.11f * (1.0f + col) | |
val y = if (isTheDraggedPiece) dndDestY else sizePx * 0.11f * (1.0f + row) | |
drawItem(x, y, sizeDp / 9, it) | |
} | |
} | |
} | |
} | |
} | |
fun DrawScope.drawCell(size: Dp, row: Int, col: Int, color: Color) { | |
val x = size.toPx() * (0.5f + col) | |
val y = size.toPx() * (0.5f + row) | |
drawRect(color = color, topLeft = Offset(x, y), size = Size(size.toPx(), size.toPx())) | |
} | |
fun DrawScope.drawItem(x: Float, y: Float, size: Dp, color: Color) { | |
drawCircle(color = color, radius = size.toPx() * 0.5f, center = Offset(x, y)) | |
} | |
@Preview | |
@Composable | |
fun ItemsGridPreview() { | |
val sizePx = with(AmbientDensity.current) { 300.dp.toPx() } | |
return ItemsGrid(sizePx) | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment