0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

【Flutter】ジェスチャーで図形を回転させてみた

Posted at

はじめに

ペイントツールを作るために、良さそうなパッケージをいくつか使ってみて、
図形の回転はどんな実装をしているのか気になったので、実装してみました

spin.gif

class MyPainter extends CustomPainter {
  const MyPainter({
    required this.angle,
  });
  final double angle;

  @override
  void paint(Canvas canvas, Size size) {
    final defaultPaint = Paint()
      ..strokeWidth = 2
      ..color = const Color(0xFF000000)
      ..style = PaintingStyle.stroke
      ..strokeCap = StrokeCap.round;

    // Flutterのキャンバスは、左上が(0, 0)の原点となる
    // プラスのx座標は右方向、プラスのy座標は下方向への移動となる
    // 100x100のRectを作成(左上の座標が(100, 100)となる)
    final rect = Rect.fromLTRB(100, 100, 200, 200);
    
    // 現在の状態を保存
    canvas.save(); 

    // Rectの中心を原点とする
    const double centerX = 150; // (100 + 200) / 2
    const double centerY = 150; // (100 + 200) / 2
    canvas.translate(centerX, centerY);

    // キャンバスを回転する
    canvas.rotate(angle);

    // 描画位置に影響するため、原点を戻す
    canvas.translate(-centerX, -centerY);

    // 四角形を描画
    canvas.drawRect(const Rect.fromLTRB(100, 100, 200, 200), defaultPaint);

    canvas.restore();
  }

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

class MyPainterPage extends StatelessWidget {
  MyPainterPage({super.key});
  final angle = ValueNotifier<double>(0);

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: SafeArea(
        child: Center(
          child: ColoredBox(
            color: Colors.orange,
            child: GestureDetector(
              onScaleUpdate: (details) {
                angle.value = details.rotation;
              },
              child: ValueListenableBuilder(
                valueListenable: angle,
                builder: (context, angle, _) {
                  return CustomPaint(
                    size: const Size(double.infinity, double.infinity),
                    painter: MyPainter(angle: angle),
                  );
                },
              ),
            ),
          ),
        ),
      ),
    );
  }
}

ポイント解説

Flutterのペイントの原点について

Flutterのペイントの原点は、デフォルトは左上(0, 0)となっている
プラスのx座標は右方向、プラスのy座標は下方向への移動となる

image.png

つまり、以下のように(10, 10)の座標に点を描画すると、左上から右に10、下に10移動した座標に点が描画される

canvas.drawPoints(PointMode.points, [const Offset(10, 10)], paint);

image.png

Rect.fromLTRBについて

下記のように実装すると、fromLTRBの引数は、下記に相当する。
L: 左の辺のx座標
T: 上の辺のy座標
R: 右の辺のx座標
B: 下の辺のy座標

final rect = Rect.fromLTRB(100, 100, 200, 200);
canvas.drawRect(rect, defaultPaint);

image.png

キャンバスの原点の移動について

canvas.translate(x, y);で原点を移動できる。
Flutterのペイントの描画は原点を基準に計算されるので、原点を移動すると描画位置が変わる。

下記のコードの場合、(10+10, 10+10)のポイントに点が描画される

canvas.translate(10, 10);
canvas.drawPoints(PointMode.points, [const Offset(10, 10)], paint);

image.png

キャンパスの原点の移動は、以下の場合に使用することが多いと思います。

  • 描画する座標を単純にする時
final rectWidth = 100;
final rectHeight = 100;
final posX = 100;
final posY = 100;
// final rect = Rect.fromLTRB(posX, posY, posX + rectWidth, posY + rectHeight);
// canvas.drawRect(rect, defaultPaint);
canvas.translate(posX, posY);
final rect = Rect.fromLTRB(0, 0, rectWidth, rectHeight);
  • 図形の回転の中心を変更する時
    次の章で解説します

キャンバスの回転について

canvas.rotate(angle)でキャンバスを回転できます。
キャンバスを回転させて、図形を描画することで、キャンバスを回転した分、図形も回転します。
例えば、下記のようにキャンバスを斜めにして、まっすぐな線を引くことで、斜めの線が引けます。
image.png

ChatGPTに聞いたところ、他にも図形を回転させる方法がありました。
① 座標計算(回転行列) を使う
② drawVertices() を使う
③ Matrix4 (Transform) を使う

キャンバスの回転の使い所としては、複数の図形をすべて回転させるケースと、描画する座標を単純にするケースで使用するみたいです。

キャンバスの状態と復元について

canvas.save()でキャンバスの回転状態と原点の位置が保存され、canvas.restore()でキャンバスの回転状態と原点の位置が一つ前の状態に戻ります。
サンプルコードだと下記の意味になります。

    // 原点(0, 0) 回転なしのデフォルトの状態を保存
    canvas.save(); 

    // 省略
    // 四角形描画
    
    // 原点(0, 0) 回転なしのデフォルトの状態に復元
    canvas.restore();
0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?