PR

[Flutter]Flutter Widget of the Week「#23 Transform」、「#24 BackdropFilter」

Flutter

はじめに

前回はFlutter Widget of the Weekの「#21 LayoutBuilder」、「#22 AbsorbPointer」を紹介しました。

今回はその続きで「#23 Transform」、「#24 BackdropFilter」の2つです。

前回の記事はこちら

Flutter Widget of the Week

環境

  • Flutter 2.10.2

記事にした時点でのバージョンです。GitHubに公開しているのは常に最新の安定版(stable)を使う予定です。

#23 Transform

Transformとは

ウィジェットを変形することができるウィジェットです。

回転拡大移動斜めにさせたり、透視図法にしたりできます。

他にもトランジションのアニメーションバウンスするカルーセル等作れたりするそうです。

サンプルコード

import 'dart:math';

import 'package:flutter/material.dart';

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

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

class _SamplePage023State extends State<SamplePage023> {
  var _offset = Offset.zero;

  @override
  Widget build(BuildContext context) {
    return Transform(
      transform: Matrix4.identity()
        ..setEntry(3, 2, 0.001)
        ..rotateX(0.01 * _offset.dy)
        ..rotateY(-0.01 * _offset.dx),
      alignment: FractionalOffset.center,
      child: GestureDetector(
        onPanUpdate: (details) => setState(() => _offset += details.delta / 2),
        onDoubleTap: () => setState(() => _offset = Offset.zero),
        child: Scaffold(
          appBar: AppBar(
            title: const Text('Transform'),
          ),
          body: SafeArea(
            child: SizedBox(
              width: double.infinity,
              child: Column(
                mainAxisAlignment: MainAxisAlignment.spaceEvenly,
                crossAxisAlignment: CrossAxisAlignment.center,
                children: [
                  Row(
                    mainAxisAlignment: MainAxisAlignment.spaceEvenly,
                    children: [
                      const Text('回転'),
                      Transform.rotate(
                        angle: pi / 4,
                        child: const _SamplePage023Icon(),
                      ),
                    ],
                  ),
                  Row(
                    mainAxisAlignment: MainAxisAlignment.spaceEvenly,
                    children: [
                      const Text('拡大'),
                      Transform.scale(
                        scale: 1.5,
                        child: const _SamplePage023Icon(),
                      ),
                    ],
                  ),
                  Row(
                    mainAxisAlignment: MainAxisAlignment.spaceEvenly,
                    children: [
                      const Text('移動'),
                      Transform.translate(
                        offset: const Offset(50, 50),
                        child: const _SamplePage023Icon(),
                      ),
                    ],
                  ),
                  Row(
                    mainAxisAlignment: MainAxisAlignment.spaceEvenly,
                    children: [
                      const Text('斜め'),
                      Transform(
                        transform: Matrix4.skewX(-0.3),
                        child: const _SamplePage023Icon(),
                      ),
                    ],
                  ),
                  Row(
                    mainAxisAlignment: MainAxisAlignment.spaceEvenly,
                    children: [
                      const Text('透視図法'),
                      Transform(
                        transform: Matrix4.identity()
                          ..setEntry(3, 2, 0.01)
                          ..rotateX(0.6),
                        alignment: FractionalOffset.center,
                        child: const _SamplePage023Icon(),
                      ),
                    ],
                  ),
                ],
              ),
            ),
          ),
        ),
      ),
    );
  }
}

class _SamplePage023Icon extends StatelessWidget {
  const _SamplePage023Icon({
    Key? key,
  }) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return Container(
      width: 64,
      height: 64,
      color: Colors.blue,
      child: const Icon(
        Icons.catching_pokemon,
        color: Colors.white,
      ),
    );
  }
}

結果

四角いウィジェットを回転させたり、透視図法にすることができました。

また、画面全体をこんな感じに回転させることもできます。

動画

公式リファレンス

Transform class - widgets library - Dart API
API docs for the Transform class from the widgets library, for the Dart programming language.

#23 BackdropFilter

BackdropFilterとは

読み込んだやアセットの画像やネットワーク経由で取得しが画像に回転やぼかしをいれたりすることのできるウィジェットです。

注意点として、BackdropFilterのchildウィジェットに影響がでるのではなく、下にいるウィジェットに効果が出るそうです。

StackとPositioned.fillを使うのが一番わかりやすいかもしれません。

サンプルコード

import 'dart:math';
import 'dart:ui';

import 'package:flutter/material.dart';

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

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

class _SamplePage024State extends State<SamplePage024> {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text('BackdropFilter'),
      ),
      body: SafeArea(
        child: Center(
          child: Column(
            children: [
              const Text('なぜかブラーがかかってしまうテキスト'),
              Stack(
                children: [
                  Image.asset(
                    'assets/genba_neko.png',
                    width: 128,
                    height: 128,
                  ),
                  Positioned.fill(
                    child: BackdropFilter(
                      filter: ImageFilter.blur(
                        sigmaX: 3,
                        sigmaY: 3,
                      ),
                      child: Container(
                        color: Colors.black.withOpacity(0),
                      ),
                    ),
                  ),
                ],
              ),
              const Text('ブラー'),
            ],
          ),
        ),
      ),
    );
  }
}

class _SamplePage023Icon extends StatelessWidget {
  const _SamplePage023Icon({
    Key? key,
  }) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return Container(
      width: 64,
      height: 64,
      color: Colors.blue,
      child: const Icon(
        Icons.catching_pokemon,
        color: Colors.white,
      ),
    );
  }
}

結果

とあるキャラクターにぼかしを入れてみました。

ただ、本来はぼかしたくないテキストまでブラーがかかってしまっているので何かしらの処理が誤っているのかもしれません。

動画

公式リファレンス

BackdropFilter class - widgets library - Dart API
API docs for the BackdropFilter class from the widgets library, for the Dart programming language.

さいごに

Transformはウィジェットの回転や変形でよく使うのでしっかり覚えておきたいです。

BackDropFilterはちょっとクセがあるので使うときは注意が必要そうです。

おすすめ参考書

リンク

GitHub - nobushiueshi/flutter_widget_of_the_week
Contribute to nobushiueshi/flutter_widget_of_the_week development by creating an account on GitHub.

コメント

タイトルとURLをコピーしました