????小菜想自定義一個水波紋按鈕洞翩,即默認向外擴散的水波樣式焊虏;實現(xiàn)方式有很多種,小菜嘗試最基本的 AnimationController 逐層繪制來處理啥容,小菜簡單記錄一下嘗試過程锈颗;
ACEWaterButton
????小菜畫了一個簡單的圖如下,預期的水波紋按鈕包括兩層干毅,以中心圓(藍色)為基礎逐步向外圍擴散至(綠色)宜猜,并循環(huán)重復;
1. 內(nèi)置圓
????小菜以此分為兩步硝逢,第一步先繪制內(nèi)置圓和內(nèi)置圖標姨拥,小菜提供了 innerSize 和 innerIcon 屬性以方便內(nèi)置圓的樣式自定義;通過 ClipOval 裁切一個完整的內(nèi)置圓渠鸽;
????其中需要注意的是叫乌,內(nèi)置圓應置于外圍圓的中心,因此小菜添加一個 outSize 屬性限制外圍圓尺寸徽缚,同時默認設置 innerSize = 48.0憨奸,若未設置 outSize,則以 innerSize * 2 為默認值凿试;
Container(
width: widget.outSize ?? widget.innerSize * 2,
height: widget.outSize ?? widget.innerSize * 2,
child: widget.innerIcon == null
? Container() : Center(child: ClipOval(
child: Container(
width: widget.innerSize,
height: widget.innerSize,
color: widget.color,
child: widget.innerIcon))))
2. 水波紋
????小菜預想實現(xiàn)水波紋效果則必然離不開 Animation 動畫排宰,使用動畫方式也有多種,可以繼承 AnimatedWidget 也可以使用 AnimationController 自定義動畫樣式那婉;
????小菜預期水波紋不僅范圍逐漸變大板甘,并且在擴散過程中透明度逐漸降低,至外圍最大范圍為止消失详炬;小菜采用最基本的 CustomPainter 自定義 Canvas.drawCircle盐类,根據(jù)時間進度來逐層繪制水波紋;
2.1 透明度
????小菜使用 Paint 繪制時根據(jù) AnimationController.value 進度逐步設置 color.withOpacity 透明度逐漸變低呛谜;
Paint _paint = Paint()..style = PaintingStyle.fill;
_paint..color = color.withOpacity(1.0 - progress);
2.2 外圍圓
????外圍圓主要是根據(jù) AnimationController.value 進度逐步進行半徑的更新在跳;小菜預期的水波紋范圍只有默認的內(nèi)置圓到外圍圓的范圍漸變,因此變動范圍為 (outSize - innerSize) * 0.5 * progress隐岛,同時起始位置為內(nèi)置圓猫妙,因此初始半徑應再加上內(nèi)置圓半徑;
double _radius = ((outSize ?? innerSize * 2) * 0.5 - innerSize * 0.5) * progress + innerSize * 0.5;
canvas.drawCircle(Offset(size.width * 0.5, size.height * 0.5), _radius, _paint);
????小菜在測試過程中也嘗試了其他的擴展范圍聚凹,若起始位置為中心則無需添加內(nèi)置圓半徑吐咳;若想增大或見效水波紋范圍可以自由調(diào)整 AnimationController.value 進度范圍逻悠;
// 中心點擴展
double _radius = innerSize * 0.5 * progress;
// 增大擴展范圍
double _radius = innerSize * 2 * progress;
class ACEWaterPainter extends CustomPainter {
final double progress;
final Color color;
final double innerSize;
final double outSize;
Paint _paint = Paint()..style = PaintingStyle.fill;
ACEWaterPainter(this.progress, this.color, this.innerSize, this.outSize);
@override
void paint(Canvas canvas, Size size) {
_paint..color = color.withOpacity(1.0 - progress);
double _radius =
((outSize ?? innerSize * 2) * 0.5 - innerSize * 0.5) * progress + innerSize * 0.5;
canvas.drawCircle(Offset(size.width * 0.5, size.height * 0.5), _radius, _paint);
}
@override
bool shouldRepaint(CustomPainter oldDelegate) => true;
}
3. 小反思
3.1 內(nèi)置圓是否可缺试韭脊?
????小菜在通過 ACEWaterPainter 繪制水波紋過程中,起始位置從內(nèi)置圓開始单旁,那是否可以省略第一步的內(nèi)置圓呢沪羔?
????暫時先不缺省,因為小菜在設置水波紋擴散過程中象浑,同時設置了透明度的漸變蔫饰,若缺省內(nèi)置圓會影響 innerIcon 的展示效果;但內(nèi)置圓繪制位置可以調(diào)整愉豺,也可以在 ACEWaterPainter 中進行繪制篓吁;
3.2 shouldRepaint 是否需要一直重繪?
????ACEWaterPainter 中是否需要一直重繪蚪拦;在使用自定義 Paint 委托類創(chuàng)建新的 CustomPaint 對象時若新實例與舊實例不同杖剪,則應返回 true,否則應返回 false驰贷;因此在水波紋過程中盛嘿,小菜默認設置為 true 進行重繪;
????小菜對 ACEWaterButton 水波紋按鈕的簡單效果已滿足括袒,但還不夠完善次兆,對于重繪的機制還需要優(yōu)化;如有錯誤锹锰,請多多指導芥炭!
來源: 阿策小和尚