【Flutter/Dart】タップ時のエフェクト実装

目次

概要

ボタンなどをタップした時、一瞬文字が薄くなったり色が変わったりするもの。
そうしないとタップされたのかかどうかがわからないためだ。
かといって、押されたときにいちいち背景色など変えていては処理が大変になる。

そこで使われるのがInkWellだ。これを使うとタップされたことが一目でわかるようになる。

ソースコード

アプリ実行部分

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

import 'Basic/BasicView.dart';


void main() {
  runApp(ProviderScope(child: MyApp()));
}

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

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Demo',
      theme: ThemeData(
        colorScheme: ColorScheme.fromSeed(seedColor: Colors.deepOrange),
        useMaterial3: true,
      ),
      home: const BasicView(title: 'Flutter Demo Home Page'),
    );
  }
}

View表示部分

import 'package:flutter/material.dart';

class BasicView extends StatefulWidget {
  const BasicView({super.key, required this.title});
  final String title;

  @override
  State<BasicView> createState() => _BasicViewState();
}

class _BasicViewState extends State<BasicView> {

  void tapped() {
    setState(() {
      text = "タップされたよ";
    });
  }

  var text = "青い部分をタップしてください";

  @override
  Widget build(BuildContext context) {
    var container = Container(
        width: 300,
        height: 300,
        child: Material(
          color: Colors.blue,
          child: InkWell(
            splashColor: Colors.green,
            borderRadius: BorderRadius.circular(0),
            onTap: () {
              tapped();
            },
          ),
        ));

    return Scaffold(
      appBar: AppBar(
        backgroundColor: Theme
            .of(context)
            .colorScheme
            .inversePrimary,
        title: Text(widget.title),
      ),
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: <Widget>[
            Text(text),
            container
          ],
        ),
      ),
    );
  }
}

デモ動画

波紋が広がるようなアニメーション(borderRadius設定時)

詳細

今回のメインとなるのは以下の部分だ。

var container = Container(
      width: 300,
      height: 300,
      child: Material(
        color: Colors.blue,
        child: InkWell(
          splashColor: Colors.green,
          borderRadius: BorderRadius.circular(0),
          onTap: () {
            tapped();
          },
        ),
      ));

今回はContainerの中に実装するようにしている。
InkWellに関してだが、公式ドキュメントには「Materialの中に書かないとエラーが起こる」ということになっている。なので、Materialの中に書く必要がある。

なので、こんな感じが基礎的な構造になると思う

Container(
  width: /* 幅 */,
  height: /* 高さ */,
  child: Material(
    child: InkWell(
      onTap: () {
        /* タップ時の処理 */
      },
    ),
  ));

また、InkWellには以下のような設定値がある。

プロパティ名設定内容
onTapタップされたときの処理
splashColorタップした時の波紋の色
例:Colors.green
borderRadiusタップした時の波紋の角丸
例:BorderRadius.circular(0)
highlightColorタップした時の色(長押しするほどこの色に近くなる)
例:Colors.yellow

こうすると、タップされたときにエフェクトが発生するようになる。
また、borderRadiusを設定すると、タップした箇所を中心に波紋が広がるようなエフェクトになる。そのときにエフェクトの色はsplashColorで設定することができる。

参考ページ