先來看圖:
我們在日常使用 APP 當中,肯定會遇到這種效果,那麼這種效果是如何實現的呢?
確認需求
首先還是老套路,先確定一下需求,捋一下思路,然後才好寫程式碼:
- 首先要有一個圓
- 這個圓會邊擴散邊消失
- 當這個圓擴散到一定程度的時候再繪製一個圓
- 有限迴圈 / 無限迴圈
- 可以有 / 無 Child
捋好了思路,下面我們來開始實現。
首先要有一個圓
首先有一個圓,這個圓應該怎麼畫?我想到了兩種方案:
- CustomPaint
- ClipOver
這兩種方式都很簡單,所以我選擇了後者,因為後者更簡單(23333)。
程式碼我就不貼了,不過程式碼我已經提交到了 github.com/wanglu1209/…
這個圓會邊擴散邊消失
一邊擴散,一邊消失。
有沒有想起來我上一篇文章說起的箭頭小Demo? --- Flutter | 通過一個小例子帶你認識動畫 Animation
沒錯,這裡也是使用這種 evaluate
來計算大小和透明度。
程式碼如下:
Container(
width: _radiusTween.evaluate(animation),
height: _radiusTween.evaluate(animation),
child: ClipOval(
child: Opacity(
opacity: _opacityTween.evaluate(animation),
child: Container(
color: color,
),
),
),
)
複製程式碼
這樣,我們只需要設定好該 Tween 的 begin 和 end 就能實現一邊擴散,一邊消失了。
當這個圓擴散到一定程度的時候再繪製一個圓
首先,我們都知道,在 Flutter 當中,如何把一個 widget 浮在另一個 widget 上。沒錯,用 Stack
。
那就要建立一個 List<Widget>
來存放我們的剛才定義好的「會擴散消失的圓」。
而且我們也知道,這個「會擴散消失的圓」需要一個 Animation
,那也就是說每一個圓都需要一個Animation
和 AnimationController
,那我們也需要建立一個 List<AnimationController>
來控制每一個「會擴散消失的圓」。
並且,在 AnimationStatus
== completed
的時候,把該 圓移除,並且把該 controller dispose。
而且在該 Widget dispose 的時候,也應該把所有未清除的 controller 給清除掉。
大致程式碼如下:
int i = 0;
while (widget.cycles == null ? true : i < widget.cycles) {
if (mounted) {
setState(() {
AnimationController _animationController;
Animation<double> _animation;
_animationController =
AnimationController(vsync: this, duration: widget.duration);
_animation = CurvedAnimation(
parent: _animationController, curve: Curves.linear);
_animationController.addStatusListener((status) {
if (status == AnimationStatus.completed) {
children.removeAt(0);
controllers.removeAt(0);
_animationController.dispose();
}
});
controllers.add(_animationController);
_animationController.forward();
widget.child != null
? children.insert(
children.length - 1,
AnimatedSpread(
animation: _animation,
radius: widget.radius,
maxRadius: widget.maxRadius,
color: widget.spreadColor,
))
: children.add(AnimatedSpread(
animation: _animation,
radius: widget.radius,
maxRadius: widget.maxRadius,
color: widget.spreadColor,
));
});
}
if (widget.cycles != null) i++;
await Future.delayed(
Duration(milliseconds: widget.duration.inMilliseconds ~/ 3));
}
複製程式碼
每一個 animation
是有 duration 的,那麼我們就可以根據該持續時間來設定什麼時候出現第二個圓,我這裡寫的是持續時間的 1/3。
這樣看起來效果是不錯的。
有限迴圈 / 無限迴圈
在剛才的程式碼裡面其實就有這一部分的邏輯:
while (widget.cycles == null ? true : i < widget.cycles) {
// ...
}
複製程式碼
這裡主要就是控制顯示幾次,畢竟有的需求不是一直顯示波紋效果。
可以有 / 無 Child
我這裡寫的 child 預設形狀是圓形的,大小被 SizedBox
控制為 radius
的大小:
ClipOval(
child: SizedBox(
width: widget.radius,
height: widget.radius,
child: widget.child,
),
),
複製程式碼
如果有 child 的話如何保證 child 永遠都是在最上面?
只需要在插入圓形的時候使用 List.insert(index, element)
方法就ok了。
這樣一個有水波紋擴散效果的 Widget 就封裝完成了。
總結
這裡我使用了和上篇文章一樣的邏輯,都是使用的 AnimatedWidget
,
然後用 Stack
來包裝,Future.delayed
來控制下一個圓形出現的時間。
另我個人建立了一個「Flutter 交流群」,可以新增我個人微信 「17610912320」來入群。
推薦閱讀:
Flutter | 通過一個小例子帶你認識動畫 Animation