How to set “z-index” of canvas elements?

夙愿已清 提交于 2021-01-27 18:12:05

问题


So I got this painter to draw a minimap for my game:

class MiniMapPainter extends CustomPainter {
  final GameMap map;
  final double tileSize;
  final List<ui.Image> images;

  MiniMapPainter(
      {@required this.images, @required this.map, @required this.tileSize});

  @override
  void paint(Canvas canvas, Size size) {
    var row = 0;
    var column = 0;

    map.encodedMap.runes.forEach((charCode) {
      final character = String.fromCharCode(charCode);

      if (character == map.rowSeparator) {
        row++;
        column = 0;
      } else if (character == map.colSeparator) {
        column++;
      } else {
        final code = map.codeFromInt(int.parse(character));
        final paint = _paintFromMapCode(code);

        switch (code) {
          case MapCode.TreasureChestClosed:
          case MapCode.TreasureChestLocked:
            _paintImageFromAsset(canvas, column, row, images[0]);
            break;
          default:
            canvas.drawRect(
                Rect.fromLTWH(
                  _getLeft(column), // Determines position on x-axis
                  _getTop(row), // Determines position on y-axis
                  tileSize,
                  tileSize,
                ),
                paint);
            break;
        }
      }
    });
  }

  double _getTop(int index) {
    return index * tileSize;
  }

  double _getLeft(int index) {
    return (index % map.columns).floor().toDouble() * tileSize;
  }

  void _paintImageFromAsset(Canvas canvas, int x, int y, ui.Image asset) {
    final size = tileSize * 3;
    final offset = (size / 2);

    paintImage(
        canvas: canvas,
        rect: Rect.fromLTWH(
          _getLeft(x) - offset,
          _getTop(y) - offset,
          size,
          size,
        ),
        image: asset);
  }

  Paint _paintFromMapCode(MapCode code) {
    var paint = Paint();

    switch (code) {
      case MapCode.Obstacle:
        paint.color = Colors.black;
        break;
      case MapCode.DamageTrap:
        paint.color = Colors.red[300];
        break;
      case MapCode.StunTrap:
        paint.color = Colors.red[100];
        break;
      default:
        paint.color = Colors.grey[300];
        break;
    }

    return paint;
  }

  @override
  bool shouldRepaint(MiniMapPainter oldDelegate) => true;
  @override
  bool shouldRebuildSemantics(MiniMapPainter oldDelegate) => true;
}

Some things require an image instead of a rectangle, such as treasures. So I added the _paintImageFromAsset method which works great but there's a problem which can be seen in this screenshot:

As you can see any rectangles drawn after the treasures seem to get a higher z-index so they clip the images.

I haven't found a way to set the z-index of custom canvas elements like this. I would like to avoid having to draw images after all the rectangles if possible.

How can I do this?


回答1:


Maybe use two widgets? e.g.

Stack(children: [
  CustomPaint(paint: ThePaintToCreateThingsWithSmallZIndex()),
  CustomPaint(paint: ThePaintToCreateThingsWithBigZIndex()),
])

By doing this, you do not need to care about the order of drawing, and even if ThePaintToCreateThingsWithSmallZIndex is painted later, it is still on below.

Do not forget to paint transparently instead of white background.

(The code is only for demo purpose and cannot be compiled, of course)




回答2:


if you really want two (or more) separate CustomPainters with a separate buffered / cached display use that function:

Widget createLayers(List<CustomPainter> painters, [Widget child = const SizedBox.expand()]) {
  painters.reversed.forEach((painter) {
    child = RepaintBoundary(
      child: CustomPaint(
        painter: painter,
        child: child,
      ),
    );
  });
  return child;
}

and the sample usage is:

SomeContainer(
  child: createLayers([SquaresPainter(), ImagesPainter()]),
)


来源:https://stackoverflow.com/questions/64400716/how-to-set-z-index-of-canvas-elements

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!