自定義一個(gè)水波進(jìn)度球
最終樣式:

1.自定義View
在Flutter中自定義View需要繼承CustomPainter控件,需要實(shí)現(xiàn)兩個(gè)方法:
void paint(Canvas canvas, Size size)以及bool shouldRepaint(CustomPainter oldDelegate),重要的方法當(dāng)然就是前者,如何在畫(huà)布上畫(huà)出我們想要的圖案;
至于CusetomPainter控件的使用如下:
Container(
width: 200.0,
height: 200.0,
child: new WavePainter(),
),
2.繪制波浪
繪制波浪的原理其實(shí)很簡(jiǎn)單,重點(diǎn)就是使用path貝塞爾曲線的使用,繪制如下:
Path path = new Path()
..moveTo(waveCenter.dx - width, waveCenter.dy)
..lineTo(waveCenter.dx - width, center.dy + height / 2)
..lineTo(waveCenter.dx + width, center.dy + height / 2)
..lineTo(waveCenter.dx + width, waveCenter.dy);
..quadraticBezierTo(
waveCenter.dx +
width*3/4,
waveCenter.dy + waveHeight,
waveCenter.dx +
width * 1/2,
waveCenter.dy)
..quadraticBezierTo(
waveCenter.dx +
width*1/4,
waveCenter.dy - waveHeight,
waveCenter.dx,
waveCenter.dy)
..quadraticBezierTo(
waveCenter.dx -
width*1/4,
waveCenter.dy + waveHeight,
waveCenter.dx -
width * 1/2,
waveCenter.dy)
..quadraticBezierTo(
waveCenter.dx -
width*3/4,
waveCenter.dy - waveHeight,
waveCenter.dx -
width,
waveCenter.dy);
然后使用canvas進(jìn)行繪制:
canvas.drawPath(path, paint);

這里其實(shí)繪制了兩段重復(fù)的波浪,然后在后面使用一個(gè)動(dòng)畫(huà)讓它向右平移width的寬度,然后重復(fù)動(dòng)畫(huà),這樣在給定的視野框中就像是波浪一直向右滾動(dòng)。
這里我們需要在波浪外套上一層圓形,然后讓圓形內(nèi)的波浪顯示,而圓形外的波浪隱藏,就使用到了paint的blendMode屬性,這個(gè)屬性的值有很多種,兄弟們自行了解,這里使用到的如下:
paint..blendMode = BlendMode.srcATop
具體代碼如下:
var paint = new Paint()
..color = circleBackgroundColor
..style = PaintingStyle.fill;
canvas.drawCircle(center, min(width, height) / 2, paint);
paint
..blendMode = BlendMode.srcATop
..style = PaintingStyle.fill
..strokeWidth = 2.0;
canvas.drawPath(paint, paint);

然后我們可以在中加入一個(gè)顯示進(jìn)度的文字,使用TextPainter進(jìn)行繪制:
TextPainter tp = TextPainter(
text: TextSpan(
text: '${(yAnimValue * 100.0).toStringAsFixed(0)}%',
style: textStyle),
textDirection: TextDirection.rtl)
..layout();
tp.paint(
canvas, Offset(center.dx - tp.width / 2, center.dy - tp.height / 2));
3.加入進(jìn)度功能
加入進(jìn)度的功能也就是為了能讓波浪能夠由下至上填滿,和波浪平移一樣,這里給一個(gè)動(dòng)畫(huà):
yController = new AnimationController(
vsync: this, duration: Duration(milliseconds: 500));
yAnimation = new Tween(begin: 0.0, end: 1.0).animate(yController);
yAnimation.addListener(_onProgressChange);
yAnimation.addStatusListener(_onProgressStatusChange);
void _onProgressChange() {
setState(() {
curProgress = yAnimation.value;
});
}
void _onProgressStatusChange(status) {
if (status == AnimationStatus.completed) {
onProgressChange();
}
}
讓后讓波浪的高度由這個(gè)動(dòng)畫(huà)數(shù)值來(lái)控制,這里刷新的遠(yuǎn)離就是當(dāng)動(dòng)畫(huà)數(shù)值變化的時(shí)候,調(diào)用StatefulWidget的setState({})進(jìn)行界面刷新。
4.波浪特效
對(duì)于滾動(dòng)的波浪我們可以加入以下特效:
paint..maskFilter = MaskFilter.blur(BlurStyle.inner, 10.0)
通過(guò)maskFilter屬性我們可以設(shè)置繪制區(qū)域高斯模糊,這里設(shè)置強(qiáng)度為10.0,方向?yàn)橄騼?nèi)
對(duì)于顯示的文字我們也加入特效:
TextStyle(
fontSize: 60.0,
foreground: Paint()
..color = Colors.lightBlue
..style = PaintingStyle.fill
..strokeWidth = 2.0
..blendMode = BlendMode.difference
..colorFilter = ColorFilter.mode(Colors.white, BlendMode.exclusion)
..maskFilter = MaskFilter.blur(BlurStyle.solid, 1.0),
fontWeight: FontWeight.bold,
),
blendMode表示繪制有重疊的區(qū)域顏色區(qū)別處理,然后colorFilter表示對(duì)繪制的顏色與白色進(jìn)行混色,就可以做出,波浪經(jīng)過(guò)的時(shí)候文字水中與不在水中的部分有不同的顏色。