1

I'm currently experimenting with the new Jetpack Compose UI toolkit and for now I really love it. With the following code I can draw any shape on the screen, make it clickable and move it around:

@Composable fun Shape( color: Color, @FloatRange(from = 0.0, to = 1.0) transparency: Float, strokeWidth: Dp, onMoveShape: (dragAmount: Offset) -> Unit, builder: Path.(size: Size, layoutDirection: LayoutDirection) -> Unit ) { val fillColor = color.copy(transparency) val drawingShape = GenericShape(builder) val position = Modifier.fillMaxSize() val border = Modifier.border(strokeWidth, color, drawingShape) val background = Modifier.background(fillColor, drawingShape) val clip = Modifier.clip(drawingShape) val clickListener = Modifier.clickable { /* ... */ } val dragListener = Modifier.draggable { change, dragAmount -> change.consumeAllChanges() onMoveShape(dragAmount) } Box(position + border + background + clip + clickListener + dragListener) } 

The onMoveShape callback moves the points used in the builder around which triggers a recomposition which works great. My problem here is that the area from where I can start the drag and click events does not update when I move the shape. I think it's best to explain that in this screenshot:

enter image description here

I removed the code for the red dots above since it is not important for the question. I guess since the click and drag listeners do not depend on the drawingShape they don't get recomposed and that's why the area is not updated. Any ideas how I can archive this?

The + for Modifier and the draggable Modifier are extension functions btw.

2 Answers 2

2

To create a clickable and draggable composable,

@Composable fun DraggableShape() { Box(modifier = Modifier.fillMaxSize()) { var offsetX by remember { mutableStateOf(0f) } var offsetY by remember { mutableStateOf(0f) } Box( Modifier .offset { IntOffset(offsetX.roundToInt(), offsetY.roundToInt()) } .background(Color.Blue) .size(50.dp) .clickable { Log.e("TAG","Clicked") } .pointerInput(Unit) { detectDragGestures { change, dragAmount -> change.consumeAllChanges() offsetX += dragAmount.x offsetY += dragAmount.y } } ) } } 

Source: Android Docs

The click events are working even after dragging.

Note:
Use pointerInput for dragging in all directions and draggable for dragging in a single direction.

If this is still not working for you, kindly provide a minimal code with the issue reproducible.
(Current code has extensions, shapes, etc and I couldn't find the exact issue in that)

Sign up to request clarification or add additional context in comments.

Comments

0

Do not place your dragListener inside your composable. If your composable recomposes, it will get destroyed and recreated causing it to lose state. Instead, pass in the the drag listener as a lamda parameter. Use state hoisting to do this. Your hoisted composable should not recompose. Placing normal listeners like click listeners inside a composable is fine because most of the time, recomposing them isn't going to effect their logic - such as a button click event. But if your listener needs to maintain state data during events like dragging, you need to maintain that state. Try something like this:

@Composable fun ShapeHandler() { val dragListener = Modifier.draggable { change, dragAmount -> change.consumeAllChanges() onMoveShape(dragAmount) } Shape( color = xxx, transparency = xxx, strokeWidth = xxx onMoveShape = xxx, builder = xxx, dragListener = dragListener ) } @Composable fun Shape( color: Color, @FloatRange(from = 0.0, to = 1.0) transparency: Float, strokeWidth: Dp, onMoveShape: (dragAmount: Offset) -> Unit, builder: Path.(size: Size, layoutDirection: LayoutDirection) -> Unit, dragListener: DragListener ) { val fillColor = color.copy(transparency) val drawingShape = GenericShape(builder) val position = Modifier.fillMaxSize() val border = Modifier.border(strokeWidth, color, drawingShape) val background = Modifier.background(fillColor, drawingShape) val clip = Modifier.clip(drawingShape) val clickListener = Modifier.clickable { /* ... */ } Box(position + border + background + clip + clickListener + dragListener) } 

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.