flutterでテキストアニメーション

flutter

はじめに

flutter勉強中です。
今回テキストアニメーションをこちらのリポジトリを参考に作成しました。
flutterのパッケージにあまり詳しくないため、すでに類似するパッケージがあるかもしれません。

完成品

左から順番に表示するテキストが確定するアニメーションを作成しました。

github

コード(全体)

main.dart

import 'package:flutter/material.dart';
import 'package:text_appear_animation/shuffle.dart';
import 'package:text_appear_animation/text_appear_animation.dart';

void main() {
  runApp(MyApp());
}

class MyApp extends StatefulWidget {
  @override
  _MyAppState createState() => _MyAppState();
}

class _MyAppState extends State<MyApp> {

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
        appBar: AppBar(
          title: const Text('example app'),
        ),
        body: Center(
          child: Container(
            width: 220,
            height: 300,
            alignment: Alignment.centerLeft,
            child: TextAppearAnimation(
              ShuffleAnimatedText('flutter'),
            )
          )
        ),
      ),
    );
  }
}

text_appear_animation.dart

import 'package:flutter/material.dart';

//インターフェースの定義
//implementsでもいいかも
abstract class AnimatedText {

  Widget animatedBuilder(BuildContext context, Widget? child);

  void initAnimation(AnimationController controller);
}

//テキストアニメーションをビルドするクラス
class TextAppearAnimation  extends StatefulWidget {

  final AnimatedText animatedText;

  const TextAppearAnimation(
    this.animatedText
  );

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

class _TextAppearAnimation extends State<TextAppearAnimation>
    with TickerProviderStateMixin {
  late AnimationController _controller;

  @override
  void initState() {
    super.initState();

    //5秒で指定した文字(今回だと「flutter」が表示される設定にする)
    _controller = AnimationController(
      duration: const Duration(seconds: 5),
      vsync: this,
    );

    widget.animatedText.initAnimation(_controller);

    //繰り返しアニメーションを実行する。1度だけ実行の場合は「_controller.forward();」。
    _controller.repeat();
  }

  @override
  void dispose() {
    _controller.dispose();
    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    return AnimatedBuilder(
      animation: _controller,
      builder: widget.animatedText.animatedBuilder,
    );
  }
}

shuffle.dart

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

class ShuffleAnimatedText extends AnimatedText{

  String text;
  late Animation<double> textTween;

  ShuffleAnimatedText(
    this.text
  );

  //5秒間で0から1へ変化するtextTweenの生成
  @override
  void initAnimation(AnimationController controller) {
    textTween = CurveTween(
      curve: Curves.linear,
    ).animate(controller);
  }

  String visibleString = '';
  String shuffleString = '';

  @override
  Widget animatedBuilder(BuildContext context, Widget? child) {

    //表示が確定した文字のインデックス
    final textValueIndex = (textTween.value.clamp(0,1) * text.length).round();

    //表示させる文字
    visibleString = text.characters.take(textValueIndex).toString();

    //シャッフルし続ける文字
    shuffleString = '';
    for(int i=0; i < text.length - textValueIndex; i++){
      var randomValue;
      var index;

      randomValue = new Random();
      index = randomValue.nextInt(text.length);
      shuffleString = shuffleString + text[index];
    }

    //表示
    return RichText(
        text: TextSpan(
          style: TextStyle(color: Colors.black, fontSize: 64),
          children: [
            TextSpan(
              text: visibleString,
            ),
            TextSpan(
              text: shuffleString,
            ),
         ],
      ),
    );
  }

}

処理の流れ

自分へのメモとしてまとめます。

アニメーションのウィジット呼び出し

アニメーションのウィジットの呼び出しです。
今回は’flutter’というテキストを表示させる指定をしています。

main.dart
TextAppearAnimation(
  ShuffleAnimatedText('flutter'),
)

初期化

1.initState内の処理が実行されます。
今回は5秒で全ての文字列(flutter)を表示させるため、5を設定しています。

text_appear_animation.dart
_controller = AnimationController(
  duration: const Duration(seconds: 5),
  vsync: this,
);



2.ShuffleAnimatedTextクラス定義の初期化処理を実行します。
補足として「widget」と書くとTextAppearAnimationにて受け取った属性へアクセスできるようになります。

text_appear_animation.dart
widget.animatedText.initAnimation(_controller);



3.ShuffleAnimatedTextクラス定義の初期化処理の実態です。
5秒間(上記AnimationControllerにて指定)で0から1へ変化する値を使用したかったため、CurveTweenにより作成しています。

shuffle.dart
 void initAnimation(AnimationController controller) {
    textTween = CurveTween(
      curve: Curves.linear,
    ).animate(controller);
  }



4.今回はアニメーションを繰り返し表示させるため、以下の通り記述してます。

text_appear_animation.dart
_controller.repeat();

アニメーションの実行

1.アニメーションさせる処理をビルドしています。

text_appear_animation.dart
  Widget build(BuildContext context) {
    return AnimatedBuilder(
      animation: _controller,
      builder: widget.animatedText.animatedBuilder,
    );
  }



2.表示が確定した文字列の処理です。
textTween.valueは5秒間かけて0から1に値変化します。
その数値に’flutter’の文字数である7を乗算することにより、5秒間かけて0から7まで変化する値を作成します。

shuffle.dart
final textValueIndex = (textTween.value.clamp(0,1) * text.length);

上記処理をround()により整数に丸め込み、表示させる文字のインデックスとして使用し、徐々に文字が確定していく処理を作り出しています。

shuffle.dart
  //表示が確定した文字のインデックス
  final textValueIndex = (textTween.value.clamp(0,1) * text.length).round();
 
  //表示させる文字
  visibleString = text.characters.take(textValueIndex).toString();



3.確定していない文字列数分ループさせ、乱数により’flutter’いずれかの文字を参照します。
参照した文字を連結することで、未確定文字を作成しています。

shuffle.dart
//シャッフルし続ける文字
shuffleString = '';
for(int i=0; i < text.length - textValueIndex; i++){
  var randomValue;
  var index;

  randomValue = new Random();
  index = randomValue.nextInt(text.length);
  shuffleString = shuffleString + text[index];
}



4.最後に表示が「確定した文字列」と「未確定の文字列」を連結させ、表示させています。

shuffle.dart
//表示
return RichText(
    text: TextSpan(
      style: TextStyle(color: Colors.black, fontSize: 64),
      children: [
        TextSpan(
          text: visibleString,
        ),
        TextSpan(
          text: shuffleString,
        ),
     ],
  ),
);

コメント

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