How to Draw multiple Rectangle with different rotation in Flutter Canvas?

Issue

I am trying to add multiple Rectangles in the Canvas and rotate them with user pan action. But the Constructor I found till now for Rect is all to draw them without Rotation. and I found a method canvas.rotate() which will rotate the whole canvas.

How to achieve this? Any code where rotation of the Rectangle is dealt with user pan action without using canvas.rotate() will be helpful.

Solution

The solution is simple as @pskink answered in the comment above.

There is only canvas.rotate() and canvas.transform() to rotate anything in the flutter canvas and there is canvas.scale() to scale them.

now if you want to rotate one object 120, and another 40 degrees you need to draw them inside a canvas.save()canvas.restore() block. then your objects will be rotated at a different angles. look at the below code for example:

import 'dart:async';
import 'dart:typed_data';

import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'dart:ui' as ui;

const kCanvasSize = 300.0;

class ImageInsideRectPage extends StatefulWidget {
  const ImageInsideRectPage({Key? key}) : super(key: key);

  @override
  _ImageInsideRectPageState createState() => _ImageInsideRectPageState();
}

class _ImageInsideRectPageState extends State<ImageInsideRectPage> {
  ui.Image? image;

  @override
  void initState() {
    _load('assets/img.png');
    super.initState();
  }

  void _load(String path) async {
    var bytes = await rootBundle.load(path);
    image = await decodeImageFromList(bytes.buffer.asUint8List());
    setState(() {});
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: Center(
        child: Container(
          decoration: BoxDecoration(
              border: Border.all(color: Colors.greenAccent, width: 2)),
          height: kCanvasSize,
          width: kCanvasSize,
          child: CustomPaint(
            painter: ImageInsideRectangle(context: context, image: image),
            child: SizedBox.expand(),
          ),
        ),
      ),
    );
  }
}

class ImageInsideRectangle extends CustomPainter {
  ImageInsideRectangle({required this.context, required this.image});
  ui.Image? image;
  final BuildContext context;

  @override
  void paint(Canvas canvas, Size size) async {
    canvas.clipRRect(ui.RRect.fromRectXY(
      Rect.fromPoints(Offset(0, 0), Offset(kCanvasSize - 4, kCanvasSize - 4)),
      0,
      0,
    ));
    Paint greenBrush = Paint()..color = Colors.greenAccent;
    if (image != null) {
      canvas.save();
      rotate(
          canvas: canvas,
          cx: image!.width.toDouble() / 2,
          cy: image!.height.toDouble() / 2,
          angle: -0.3);
      canvas.scale(kCanvasSize / image!.height);
      canvas.drawImage(image!, Offset(0, 0), greenBrush);
      canvas.restore();
    }
    canvas.save();
    rotate(canvas: canvas, cx: 200 + 50, cy: 100 + 50, angle: 0.5);
    canvas.drawRect(Rect.fromLTWH(200, 100, 100, 100), greenBrush);
    canvas.restore();
  }

  void rotate(
      {required Canvas canvas,
      required double cx,
      required double cy,
      required double angle}) {
    canvas.translate(cx, cy);
    canvas.rotate(angle);
    canvas.translate(-cx, -cy);
  }

  @override
  bool shouldRepaint(covariant CustomPainter oldDelegate) {
    return true;
  }
}

Future<ui.Image> loadUiImage(String imageAssetPath) async {
  final ByteData data = await rootBundle.load(imageAssetPath);
  final Completer<ui.Image> completer = Completer();
  ui.decodeImageFromList(Uint8List.view(data.buffer), (ui.Image img) {
    return completer.complete(img);
  });
  return completer.future;
}

This way you can rotate multiple objects in multiple directions. also, there is an example of loading an image from local asset and rotating it around its own center.

Answered By – Zihan

Answer Checked By – Mary Flores (FlutterFixes Volunteer)

Leave a Reply

Your email address will not be published. Required fields are marked *