使用AnimationController控制兩種動畫效果局嘁,分別是縮放動畫ScaleTransition和淡出動畫FadeTransition,多圈波紋需要多個AnimationController,把所有controller放在數(shù)組里退出時一并銷毀,
波紋widget以Stack結(jié)構(gòu)層層疊加
完整代碼:
import 'dart:async';
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
class WaveBorder extends StatefulWidget {
final Widget child; // 子控件
final int count; // 波紋圈數(shù)
final double width; // 波紋直徑
final double maxWidth; // 波紋擴(kuò)散后最大直徑
final Color borderColor; // 波紋邊框顏色
final double borderWidth; // 波紋粗細(xì)
final Duration duration; // 波紋擴(kuò)散動畫時長(毫秒)
WaveBorder({
Key key,
this.child,
this.count = 1,
this.width,
this.maxWidth,
this.borderColor = Colors.white,
this.borderWidth = 1,
this.duration = const Duration(milliseconds: 5000),
}) : super(key: key);
@override
_WaveBorderState createState() => _WaveBorderState();
}
class _WaveBorderState extends State<WaveBorder> with TickerProviderStateMixin {
List<AnimationController> _controllerList = []; // 動畫控制器數(shù)組
List<Widget> children = []; // 子組件數(shù)組(所有波紋 + child)
@override
void initState() {
super.initState();
// 配置動畫和子控件
configAnimation();
}
configAnimation() {
for (int i = 0; i < widget.count; i++) {
// 動畫控制器
var controller = AnimationController(
vsync: this,
duration: widget.duration,
);
// 控制器放數(shù)組里方便銷毀
_controllerList.add(controller);
// 波紋放大比例
double endScale = widget.maxWidth / widget.width;
// 放大動畫
var scaleAnimation = Tween(
begin: 1.0,
end: endScale,
).animate(controller);
// 透明動畫
var opacityAnimation = Tween(
begin: 1.0,
end: 0.0,
).animate(controller);
// 添加波紋組件
children.add(_borderWidget(scaleAnimation, opacityAnimation));
// 每道波紋動畫間隔
int interval = widget.duration.inMilliseconds ~/ widget.count;
Future.delayed(Duration(milliseconds: i * interval), () {
// 執(zhí)行動畫
if (mounted) {
controller.repeat();
}
});
}
// 添加子控件child
if (widget.child != null) {
children.add(widget.child);
}
}
@override
void dispose() {
// 銷毀動畫控制器
_controllerList.forEach((controller) {
controller.dispose();
});
super.dispose();
}
@override
Widget build(BuildContext context) {
return Stack(
alignment: Alignment.center,
children: children,
);
}
Widget _borderWidget(Animation scaleAnimation, Animation opacityAnimation) {
return ScaleTransition(
alignment: Alignment.center,
scale: scaleAnimation,
child: FadeTransition(
opacity: opacityAnimation,
child: Container(
width: widget.width,
height: widget.width,
decoration: BoxDecoration(
color: Colors.transparent,
borderRadius: BorderRadius.circular(widget.width / 2),
border: Border.all(color: widget.borderColor, width: widget.borderWidth),
),
),
),
);
}
}
使用:
WaveBorder(
width: 200.w,
maxWidth: 300.w,
count: 2,
borderColor: Colors.white,
borderWidth: 1,
duration: Duration(milliseconds: 4000),
child: MusicPlayBtn(playing: isPlaying.value),
);