PR

[Flutter]Flutter Widget of the Week「#70 ShaderMask」、「#71 NotificationListener」、「#72 Builder」

Flutter

はじめに

前回はFlutter Widget of the Weekの「#67 Drawer」、「#68 SnackBar」、「#69 ListWheelScrollView」を紹介しました。

今回はその続きで「#70 ShaderMask」、「#71 NotificationListener」、「#72 Builder」の3つです。

前回の記事はこちら

Flutter Widget of the Week

環境

  • Flutter 3.0.5

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

#70 ShaderMask

ShaderMaskとは

ShaderMaskを利用するとウィジェットに対してシェーダーを適用することができます。

シェーダーとは陰影をつけたり、グラデーションをつけたりすることを言います。

サンプルコード

import 'dart:ui' as ui;

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

class SamplePage070 extends StatelessWidget {
  const SamplePage070({
    super.key,
  });

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text('ShaderMask'),
        centerTitle: true,
      ),
      body: SafeArea(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: [
            Center(
              child: ShaderMask(
                shaderCallback: (bounds) => const RadialGradient(
                  colors: [
                    Colors.yellow,
                    Colors.deepOrange,
                  ],
                  tileMode: TileMode.mirror,
                ).createShader(bounds),
                child: Text(
                  'Burning Text!',
                  style: TextStyle(
                    color: Colors.white,
                    fontSize: Theme.of(context).textTheme.headline4!.fontSize,
                  ),
                ),
              ),
            ),
            const SizedBox(height: 30),
            Center(
              child: FutureBuilder<ui.Image>(
                future: _loadImage(),
                builder: (context, snapshot) {
                  if (snapshot.connectionState == ConnectionState.waiting) {
                    return const CircularProgressIndicator();
                  }
                  final image = snapshot.data!;
                  return ShaderMask(
                    blendMode: ui.BlendMode.overlay,
                    shaderCallback: (bounds) => ImageShader(
                      image,
                      TileMode.mirror,
                      TileMode.mirror,
                      Matrix4.identity().storage,
                    ),
                    child: const Icon(
                      Icons.person,
                      color: Colors.white,
                      size: 128,
                    ),
                  );
                },
              ),
            ),
          ],
        ),
      ),
    );
  }

  Future<ui.Image> _loadImage() async {
    final imageBytes = await rootBundle.load('assets/sample.png');
    return decodeImageFromList(imageBytes.buffer.asUint8List());
  }
}

結果

動画

公式リファレンス

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

#71 NotificationListener

NotificationListenerとは

通知をディスパッチすることができるウィジェットです。

ListViewなどで利用する場合はScrollNotificationがディスパッチできます。

サンプルコード

import 'package:flutter/material.dart';

class SamplePage071 extends StatelessWidget {
  const SamplePage071({
    super.key,
  });

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text('NotificationListener'),
        centerTitle: true,
      ),
      body: SafeArea(
        child: NotificationListener<ScrollNotification>(
          onNotification: (notification) {
            debugPrint(notification.toString());
            return true;
          },
          child: ListView(
            children: List.generate(
              20,
              (index) => ListTile(
                title: Text('index : $index'),
              ),
            ),
          ),
        ),
      ),
    );
  }
}

結果

スクロールするたびに以下のようなログが出ます。

flutter: ScrollStartNotification(depth: 0 (local), FixedScrollMetrics(0.0..[707.0]..413.0), DragStartDetails(Offset(140.3, 693.3)))
flutter: ScrollEndNotification(depth: 0 (local), FixedScrollMetrics(0.0..[707.0]..413.0), DragEndDetails(Velocity(0.0, 0.0)))

動画

公式リファレンス

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

#72 Builder

Builderとは

同一のビルドメソッド内で子ウィジェットが親ウィジェットのビルドコンテキストを参照する場合に利用します。

とくにScaffold,Navigator,ThemeData,MediaQuery,Provider等の継承ウィジェットを参照するような場合に必要になってきます。

サンプルコード

import 'package:flutter/material.dart';

class SamplePage072 extends StatelessWidget {
  const SamplePage072({
    super.key,
  });

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text('Builder'),
        centerTitle: true,
      ),
      body: SafeArea(
        child: Center(
          child: Column(
            mainAxisAlignment: MainAxisAlignment.center,
            children: [
              ElevatedButton(
                onPressed: () {
                  // ignore: deprecated_member_use
                  Scaffold.of(context).showSnackBar(
                    const SnackBar(
                      content: Text('通知されない'),
                    ),
                  );
                },
                child: const Text('エラーが発生するボタン'),
              ),
              const SizedBox(height: 30),
              Builder(
                builder: (context) {
                  return ElevatedButton(
                    onPressed: () async {
                      // ignore: deprecated_member_use
                      Scaffold.of(context).showSnackBar(
                        const SnackBar(
                          content: Text('通知される'),
                        ),
                      );
                    },
                    child: const Text('普通のボタン'),
                  );
                },
              ),
            ],
          ),
        ),
      ),
    );
  }
}

結果

エラーが発生するボタンを押すとExceptionを吐きます。

════════ Exception caught by gesture ═══════════════════════════════════════════
Scaffold.of() called with a context that does not contain a Scaffold.
════════════════════════════════════════════════════════════════════════════════

普通のボタンの場合は問題なし

動画

公式リファレンス

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

さいごに

NotificationListenerは、どういう場面で使うのかよくわかりませんでした。

おすすめ参考書

リンク

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

コメント

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