📑

【Flutter Widget of the Week #23】Transformを使ってみた

2022/11/12に公開

はじめに

Flutter Widget of the Week #23 Transform についてまとめましたので、紹介します。
https://youtu.be/9z_YNlRlWfA

Transform

今回紹介する Transform widget を使えば、単純なアプリでも Flutter が自らレンダリング(描画)してくれて、以下のように多彩なアニメーションを実現できます。
Transform 例1
面白いアニメーション
Transform 例2
45度回転するメニューアイコン
Transform 例3
おしゃれなアニメーションのトランジション
Transform 例4
バウンスするカルーセル
Transform 例5
かっこいいメニュー
では、サンプルコードを動かして使い方を見てみましょう。

Transform サンプルコード

Transform を使ったサンプルをいくつか紹介します。
まずは、何も Transform を使っていない場合のものです。
Transform なしの場合
Transform なしの場合

サンプルコード全体

main.dart
class TransformRotate extends StatelessWidget {
  const TransformRotate({super.key});

  
  Widget build(BuildContext context) {
    const TextStyle style = TextStyle(color: Colors.white);

    return Container(
      color: Colors.white,
      //// ここから
      child: Center(
        child: const Padding(
          padding: EdgeInsets.all(30),
          child: FlutterLogo(
            size: 150,
          ),
        ),
      ),
      ///// ここまで
    );
  }
}

※以降は上記の 変更点(ここから〜ここまでの Center のところだけ)をコードとして記載します。

①Rotate で widget を45度回転する

Rotate で widget を45度回転する場合
Rotate で widget を45度回転する場合

Center(
  child: Transform.rotate(
    angle: math.pi / 4,
    child: const Padding(
      padding: EdgeInsets.all(30),
      child: FlutterLogo(
        size: 150,
      ),
    ),
  ),
),

②Scale で widget を拡大縮小する

Scale で widget を拡大縮小する場合
Scale で widget を拡大縮小する場合

Center(
  child: Transform.scale(
    scale: 3.0,
    child: const Padding(
      padding: EdgeInsets.all(30),
      child: FlutterLogo(
        size: 150,
      ),
    ),
  ),
),

③Translate で widget の位置を変える

Translate で widget の位置を変える場合
Translate で widget の位置を変える場合

Center(
  child: Transform.translate(
    offset: Offset(50, 50),
    child: const Padding(
      padding: EdgeInsets.all(30),
      child: FlutterLogo(
        size: 150,
      ),
    ),
  ),
),

④Skew で widget の傾きを変える

Skew で widget の傾きを変える場合
Skew で widget の傾きを変える場合

Center(
  child: Transform(
    transform: Matrix4.skewX(0.3),
    child: const Padding(
      padding: EdgeInsets.all(30),
      child: FlutterLogo(
        size: 150,
      ),
    ),
  ),
),

⑤3D で widget の見た目を変える patern1

3D で widget の見た目を変える patern1場合
3D で widget の見た目を変える patern1場合

Center(
  child: Transform(
    transform: Matrix4.identity()
      ..setEntry(3, 2, 0.01)
      ..rotateX(0.6),
    alignment: FractionalOffset.center,
    child: const Padding(
      padding: EdgeInsets.all(30),
      child: FlutterLogo(
        size: 150,
      ),
    ),
  ),
),

⑥3D で widget の見た目を変える patern2

3D で widget の見た目を変える patern2場合
3D で widget の見た目を変える patern2場合

class Transform3D extends StatefulWidget {
  Transform3D(); // changed

  
  _Transform3DState createState() => _Transform3DState();
}

class _Transform3DState extends State<Transform3D> {
  int _counter = 0;
  Offset _offset = Offset(0.4, 0.7); // new

  void _incrementCounter() {
    setState(() {
      _counter++;
    });
  }

  
  Widget build(BuildContext context) {
    return Transform(
      // Transform widget
      transform: Matrix4.identity()
        ..setEntry(3, 2, 0.001) // perspective
        ..rotateX(_offset.dy)
        ..rotateY(_offset.dx),
      alignment: FractionalOffset.center,
      child: _defaultApp(context),
    );
  }

  _defaultApp(BuildContext context) {
    // new
    return Scaffold(
      appBar: AppBar(
        title: const Text('The Matrix 3D'), // changed
      ),
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: [
            const Text(
              'You have pushed the button this many times:',
            ),
            Text(
              '$_counter',
              // style: Theme.of(context).textTheme.display1,
            ),
          ],
        ),
      ),
      floatingActionButton: FloatingActionButton(
        onPressed: _incrementCounter,
        tooltip: 'Increment',
        child: const Icon(Icons.add),
      ),
    );
  }
}

これをうまく活用すると以下のようなアニメーションも作ることができます。
3D アニメーション例
3D アニメーション例

最後に

今回は Transform を紹介しました。ちょっとUIを面白くしたいと思ったときに Transform が効果的だと思うので、是非使ってみてください。
次は #24 BackdropFilter です。またお会いしましょう。

参考記事

https://api.flutter.dev/flutter/widgets/Transform-class.html
https://medium.com/flutter/perspective-on-flutter-6f832f4d912e

Discussion