“這是我參與8月更文挑戰的第4天,活動詳情檢視: 8月更文挑戰” juejin.cn/post/698796…
小菜繼續完善前兩天自定義 ACEWave 波浪元件,小菜預期的效果是多條波浪,漸變顏色,波浪寬高自定義等;
1. 區分波浪寬度動畫
小菜上一節測試時波浪寬度小於螢幕寬度,當放大波浪寬度時,迴圈過程中動畫會跳動一下,不順暢;其原因是 Animation 動畫設定有問題;
小菜調整了平移動畫的 Offset 位置,並設定波浪起始位置偏移量與小波浪時相反;
return Transform.translate(
offset: Offset(waveWidth * _curvedAnimation.value, 0.0),
child: Container(); // 波浪
複製程式碼
2. 填充波浪顏色
再此之前小菜嘗試的均為線條波浪,小菜理想的效果的是有填充色的,於是設定三屏波浪最末點與三屏波浪的最初點,通過 lineTo 連線起來,並設定 Paint 畫筆為填充效果;
Path _wavePath(path, size, plusWidth) {
for (int i = 0; i < _count; i++) {
path.moveTo(waveWidth * i - size.width - startOffset, startOffsetY);
path.quadraticBezierTo(
_quaterWidth + waveWidth * i - size.width - startOffset, startOffsetY - waveHeight,
_quaterWidth * 2 + waveWidth * i - size.width - startOffset, startOffsetY);
path.moveTo(_quaterWidth * 2 + waveWidth * i - size.width - startOffset, startOffsetY);
path.quadraticBezierTo(
_quaterWidth * 3 + waveWidth * i - size.width - startOffset, startOffsetY + waveHeight,
_quaterWidth * 4 + waveWidth * i - size.width - startOffset, startOffsetY);
path.moveTo(_quaterWidth * 4 + waveWidth * i - size.width - startOffset, startOffsetY);
}
path.lineTo(_quaterWidth * 4 + waveWidth * (_count - 1) - size.width - startOffset, 600.0);
path.lineTo(-size.width - startOffset, 600.0);
path.lineTo(-size.width - startOffset, startOffsetY);
for (int i = 0; i < _count; i++) {
path.moveTo(waveWidth * i - startOffset + plusWidth, startOffsetY);
path.quadraticBezierTo(
_quaterWidth + waveWidth * i - startOffset + plusWidth, startOffsetY - waveHeight,
_quaterWidth * 2 + waveWidth * i - startOffset + plusWidth, startOffsetY);
path.moveTo(_quaterWidth * 2 + waveWidth * i - startOffset + plusWidth, startOffsetY);
path.quadraticBezierTo(
_quaterWidth * 3 + waveWidth * i - startOffset + plusWidth, startOffsetY + waveHeight,
_quaterWidth * 4 + waveWidth * i - startOffset + plusWidth, startOffsetY);
path.moveTo(_quaterWidth * 4 + waveWidth * i - startOffset + plusWidth, startOffsetY);
}
path.lineTo(_quaterWidth * 4 + waveWidth * (_count - 1) - startOffset + plusWidth, 600.0);
path.lineTo(-startOffset + plusWidth, 600.0);
path.lineTo(-startOffset + plusWidth, startOffsetY);
for (int i = 0; i < _count; i++) {
path.moveTo(waveWidth * i + size.width - startOffset + plusWidth * 2, startOffsetY);
path.quadraticBezierTo(
_quaterWidth + waveWidth * i + size.width - startOffset + plusWidth * 2, startOffsetY - waveHeight,
_quaterWidth * 2 + waveWidth * i + size.width - startOffset + plusWidth * 2, startOffsetY);
path.moveTo(
_quaterWidth * 2 + waveWidth * i + size.width - startOffset + plusWidth * 2, startOffsetY);
path.quadraticBezierTo(
_quaterWidth * 3 + waveWidth * i + size.width - startOffset + plusWidth * 2,
startOffsetY + waveHeight, _quaterWidth * 4 + waveWidth * i + size.width - startOffset + plusWidth * 2, startOffsetY);
path.moveTo(_quaterWidth * 4 + waveWidth * i + size.width - startOffset + plusWidth * 2, startOffsetY);
}
path.lineTo(
_quaterWidth * 4 + waveWidth * (_count - 1) + size.width - startOffset + plusWidth * 2, 600.0);
path.lineTo(size.width - startOffset + plusWidth * 2, 600.0);
path.lineTo(size.width - startOffset + plusWidth * 2, startOffsetY);
return path;
}
複製程式碼
3. 波浪漸變色
小菜填充完波浪顏色之後,想進一步實現波浪漸變色,可以通過 Paint 畫筆來設定 shader 漸變效果;其中線性漸變的起始點從波峰開始,至最底部為止;
Paint paint = Paint()
..color = Colors.blue ..strokeCap = StrokeCap.round ..strokeWidth = 6
..style = PaintingStyle.fill;
var rect = Offset(0.0, startOffsetY) & Size(size.width, size.height)
paint.shader = LinearGradient(
begin: Alignment.bottomCenter,
end: Alignment.topCenter,
colors: [Colors.blue.withOpacity(0.4), Colors.white.withOpacity(0.4) ]).createShader(rect);
複製程式碼
4. 裁剪波浪
小菜設定的波浪高度預設是填充滿父控制元件的,但若父控制元件高度小於波浪的波峰到波谷高度時,波谷依然繪製出來,此時小菜通過裁剪方式,只展示設定的最高高度即可;此時注意優先設定裁剪範圍,之後再進行波浪的繪製;
canvas.save();
canvas.clipPath(_clipPath(size, _plusWidth));
canvas.drawPath(_wavePath(size, _plusWidth), paint);
canvas.restore();
複製程式碼
5. 設定多條波浪
小菜想一次性展示多條波浪,於是將各個自定義引數型別及動畫 Animation 放在 List 中,只需在初始化時傳遞多條資料即可;其中包括波浪寬高,一個波浪動時長,初始橫縱偏移量以及漸變色波浪顏色等;
// 波浪整體高度(裁剪後)
final double allHeight;
// 一個週期波浪寬度 List
final List<double> waveWidthList;
// 波峰到中心點高度 List
final List<double> waveHeightList;
// 水平偏移量 List
final List<double> startOffsetXList;
// 波峰距頂點偏移量 List
final List<double> startOffsetYList;
// 時間 List
final List<Duration> durationList;
// 漸變色 List
final List<List<Color>> waveColorList;
ACEWave(this.waveWidthList, this.waveHeightList, this.allHeight,
{this.durationList,
this.startOffsetXList,
this.startOffsetYList,
this.waveColorList});
複製程式碼
List<double> waveWidth = [600, 800, 300];
List<double> waveHeight = [60, 80, 70];
List<double> startOffsetX = [30, 150, 100];
List<double> startOffsetY = [100, 120, 100];
List<Duration> duration = [
Duration(milliseconds: 6000),
Duration(milliseconds: 4000),
Duration(milliseconds: 5000)
];
List<List<Color>> colorList = [
[Colors.green.withOpacity(0.2), Colors.white.withOpacity(0.4)],
[Colors.blue.withOpacity(0.2), Colors.white.withOpacity(0.4)],
[Colors.blue.withOpacity(0.2), Colors.white.withOpacity(0.4)]
];
return Scaffold(
appBar: AppBar(title: Text('ACEWave Page')),
body: Container(
color: Colors.grey,
height: (MediaQuery.of(context).size.height),
child: Container(
child: ACEWave(
waveWidth,
waveHeight,
300.0,
startOffsetXList: startOffsetX,
startOffsetYList: startOffsetY,
durationList: duration,
waveColorList: colorList,
))));
複製程式碼
至此,小菜自定義的波浪效果基本完成,其中對於效能和異常的處理還為完善;如有錯誤,請多多指導!
來源: 阿策小和尚