0

What are the techniques for not having to redraw the entire content of a Canvas on every redraw? For instance, if a Canvas is displaying a top-down view of a chess game and I want to remove a piece, I'd like to redraw just the part of the Canvas where the piece is removed. In my current implementation, if I update only a section of the Canvas and don't redraw the entire board I'm left with only the updated section displayed.

I've tried methods suggested by Chat GPT such as redrawing the updated area with a clipRect, using drawWithContent(), and drawing to the underlying native canvas. Maybe I didn't use the techniques correctly, but nothing seemed to work and I still redraw the entire board with every recompose even though only a little bit of the board actually has changed.

Below is how I'm currently updating Canvas. appVM is a ViewModel that processes user clicks on the board. Based on the clicks, appVM sets the state variable gameCngState to request the board to be updated in various ways (select/deselect a piece to move, select/deselect a destination, etc). Right now, instead of drawing just the parts of the board that changed, I redraw the entire board. Otherwise, I only see the parts that changed.

Box(
    modifier = Modifier
        .fillMaxSize()
        .pointerInput(Unit) {
            detectTapGestures(
                onTap = { offset -> appVM.onClick(offset) }
            )
         }
    }
) { 
    Canvas(
        modifier = Modifier
            .fillMaxSize()
            .clipToBounds()
            .onSizeChanged { size -> appVM.onSizeChange(size) }
    ) {
        appVM.onCanvasDraw(
            drawScope = this, 
            gameCngState = gameCngState
        )
      }

The below code shows how the drawing of each board square is performed. The transform places the square/piece at the correct location on the Canvas.

drawScope.translate(left = transLeft, top = transTop)
    {
        drawPath(...)  // draw square with optional piece
    }
Bill Hall
  • 13
  • 4

1 Answers1

0

Canvas is Spacer with Modifier.drawBehind{} which doesn't trigger recomposition on each draw.

Compose has 3 phases. Composition, Layout and Draw which you only call draw phase when you draw anything on Canvas unless you read a value somewhere else.

You can also refer answers below which you perform animations only 1 or zero recompositions.

Is it possible to change the size of the Image composable without triggering recomposition

https://stackoverflow.com/a/73274631/5457853

Thracian
  • 43,021
  • 16
  • 133
  • 222
  • Thracian, thanks for the tips. I'll be using them. When the system requests a Canvas redraw, is there any way to draw only the parts of a Canvas that have changed since the last drawing and skip redrawing the parts that haven't changed, or do I always have to draw the entire Canvas? – Bill Hall Apr 10 '23 at 21:28
  • Although I have not yet found documentation for this behavior, it seems that the Canvas() composable clears the canvas when it invokes its onDraw() function. This would explain why I have to redraw the entire canvas and not just what has changed since the last onDraw(). – Bill Hall Jun 09 '23 at 22:52