遮罩歌词的原理
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<ParentingAnimationWidget>
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<double>(
begin: 0,
end: 1,
).animate(CurvedAnimation(
parent: _controller,
curve: Curves.fastOutSlowIn,
));
widthTween = Tween<double>(
begin: 0,
end: 500,
).animate(CurvedAnimation(
parent: _controller,
curve: Curves.fastOutSlowIn
));
opacityTween = Tween<double>(
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: <Widget>[
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),)),
)
],
)));
});
}
}