👌

【Flutter】コピペで出来る波紋アニメーション!

2020/12/06に公開

使い所が少ないと思いますが。。。
早速スクショとサンプルコードを貼ります。

こんな感じのやつです。

simple_ripples

サンプルコード

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

class MyHomePage extends StatefulWidget {
  MyHomePage({Key key, this.title}) : super(key: key);
  final String title;

  
  _MyHomePageState createState() => _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage> with TickerProviderStateMixin {
  AnimationController _animationController;

  
  void initState() {
    super.initState();
    _animationController = AnimationController(
      vsync: this,
      duration: const Duration(milliseconds: 2000),
    )..repeat(reverse: false);
    _animationController.repeat(
      period: Duration(milliseconds: 1000), // 波紋が作成される速度
    );
  }

  
  void dispose() {
    _animationController.dispose();
    super.dispose();
  }
  
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text(widget.title),
      ),
      body: Center(
        child: CustomPaint(
          painter: SpritePainter(
            _animationController,
          ),
          child: SizedBox(
            width: 300.0,
            height: 300.0,
          ),
        ),
      ),
    );
  }
}

class SpritePainter extends CustomPainter {
  final Animation<double> _animation;

  SpritePainter(this._animation) : super(repaint: _animation);

  void circle(Canvas canvas, Rect rect, double value) {
    double opacity = (1.0 - (value / 4.0)).clamp(0.0, 1.0); // 透明度の設定
    Color color = Color.fromRGBO(192, 192, 192, opacity); // 色の設定

    double size = rect.width / 2;
    double area = size * size;
    double radius = sqrt(area * value / 4);

    final Paint paint = Paint()..color = color;
    canvas.drawCircle(rect.center, radius, paint);
  }

  
  void paint(Canvas canvas, Size size) {
    Rect rect = Rect.fromLTRB(0.0, 0.0, size.width, size.height);

    for (int wave = 3; wave >= 0; wave--) {
      circle(canvas, rect, wave + _animation.value);
    }
  }

  
  bool shouldRepaint(SpritePainter oldDelegate) {
    return false;
  }
}

Stackウィジェットを使って画像やアイコンと組み合わせると、
このようにオーラ的なUIを実装できます。

ripples_with_old_guy

body: Center(
  child: Stack(
    alignment: Alignment.center,
    children: [
      CustomPaint(
        painter: SpritePainter(
          _animationController,
        ),
        child: SizedBox(
          width: 300.0,
          height: 300.0,
        ),
      ),
      SizedBox(
        width: 150,
        height: 150,
        child: CircleAvatar(
          backgroundColor: Colors.transparent,
          backgroundImage: const AssetImage(
            'assets/images/old_guy.png',
          ),
        ),
      ),
    ],
  ),
),

まとめ

このUIは色々と使い所がありそうなので、知っておくと便利そう!
また便利そうなUIの実装をしたら、共有したいと思います。

ではさいなら〜!

Discussion