Flutter制作歌词遮罩渐变动画

遮罩歌词的原理

1.我们知道使用Flash可以很容易的制作一个遮罩的动画,以便于显示歌词的进度。原理是在第一层显示动画歌词,第二层显示的是原歌词,在顶层创建一个渐变的矩形,它从宽度为0到宽度增加到覆盖歌词的宽度并作为一个遮罩层,这样歌词便会被遮住,随着动画的进行,歌词会慢慢浮现。

2.使用flutter的ShaderMask可制作这样的动画

ShaderMask(
                        
                        child: Center(child: new Text(
                          '天青色等烟雨,而我在等你',
                        )
                          ),

                          
                        shaderCallback: (rect) {
                          print(rect.width);
                          return LinearGradient(
                            colors: [
                              Colors.greenAccent,
                              Colors.transparent,
                            ],
                            begin: Alignment.centerLeft,
                            end: Alignment.centerRight,
                            stops: [stopTween.value, 1],
                          ).createShader(rect);
                        },

child可以显示歌词,在shaderCallback中它接受一个shape的类型,也就是一个图形,rect一个矩形,在这个矩形中使用了线性渐变即 LinearGradient,stop这个属性,它随着动画值来移动渐变的停止点,以此形成渐变的动画了。
3.使用stack叠加一个原歌词text

Stack(
....
Opacity(
                        opacity: opacityTween.value,
                        child: Center(child: Text('天青色等烟雨,而我在等你', style: TextStyle(color: Colors.black38),)),
                      )

在下面使用了透明组件,将原歌词从不透明到透明动画缓缓显示出来,到原歌词透明度从1到0, 那么下面的渐变歌词就显示出来了。
4.具体的问题
我们的问题在于并不是使用宽度渐变来制作,这样歌词动画显示不是很自然的。我们可以多调整flutter 动画组件的曲线来测试出最好的值设置动画,使其更加的自然流畅。
5.代码

import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:flutter/rendering.dart';

class ParentingAnimationWidget extends StatefulWidget {
  @override
  ParentingAnimationWidgetState createState() =>
      ParentingAnimationWidgetState();
}

class ParentingAnimationWidgetState extends State
    with TickerProviderStateMixin {
  Animation opacityTween;
  Animation widthTween;
  Animation stopTween;
  AnimationController _controller;

  @override
  void dispose() {
    // TODO: implement dispose
    _controller.dispose();
    super.dispose();
  }

  @override
  void initState() {
    super.initState();
    _controller = AnimationController(
        duration: const Duration(milliseconds: 3100), vsync: this)
      ..addStatusListener((status) {
        if (status == AnimationStatus.completed) {
          setState(() {
            _controller.reset(); // 在动画状态是完成的时候,再进行重置
            _controller.forward(); // 在动画状态是完成的时候,再进行开始动画。
          });
        }
      });

    stopTween = Tween(
      begin: 0,
      end: 1,
    ).animate(CurvedAnimation(
      parent: _controller,
      curve: Curves.fastOutSlowIn,
    ));

    widthTween = Tween(
      begin: 0,
      end: 500,
    ).animate(CurvedAnimation(
      parent: _controller,
      curve: Curves.fastOutSlowIn
    ));
    
    opacityTween = Tween(
      begin: 1,
      end: 0,
    ).animate(
      CurvedAnimation(
        parent: _controller,
        curve: Curves.easeIn
      )
    );
    _controller.forward();
  }


  @override
  @override
  Widget build(BuildContext context) {
    return AnimatedBuilder(
        animation: _controller,
        builder: (BuildContext context, Widget child) {
          return Scaffold(
              appBar: new AppBar(
                title: new Text('歌词遮罩显示'),
              ),
              body: MediaQuery.removePadding(
                  context: context,
                  removeTop: true,
                  child: Stack(
                    children: [
                      ShaderMask(
                        
                        child: Center(child: new Text(
                          '天青色等烟雨,而我在等你',
                        )
                          ),

                          
                        shaderCallback: (rect) {
                          print(rect.width);
                          return LinearGradient(
                            colors: [
                              Colors.greenAccent,
                              Colors.transparent,
                            ],
                            begin: Alignment.centerLeft,
                            end: Alignment.centerRight,
                            stops: [stopTween.value, 1],
                          ).createShader(rect);
                        },
                        
                        blendMode: BlendMode.srcATop,
                      ),
                      Opacity(
                        opacity: opacityTween.value,
                        child: Center(child: Text('天青色等烟雨,而我在等你', style: TextStyle(color: Colors.black38),)),
                      )
                    ],
                  )));
        });
  }
}

你可能感兴趣的:(Flutter制作歌词遮罩渐变动画)