我有一个Paint
对象,我正在尝试使用canvas.drawArc
绘制弧度,但唯一的方法(至少根据我的研究)是使用Shader
,但从Shader
得到一个Gradient
对象,你必须使用Gradient.createShader(Rect rect)
,它采用矩形。我的问题是,有没有办法为Arc而不是Rectangle创建着色器?这是我到目前为止的参考资料:
Paint paint = new Paint()
..color = bgColor
..strokeCap = StrokeCap.round
..strokeWidth = 3.0
..style = PaintingStyle.stroke
..shader = new Gradient.radial(size.width / 2.0, size.height / 2.0, size.height / 3.0, Colors.transparent, timerColor, TileMode.mirror).createShader(/* I don't have a rect object */);
canvas.drawArc(..., paint);
您需要的矩形实际上是一个正方形,您绘制的圆将适合该正方形。圆弧只是从那个圆圈中掠过这么多弧度的一片馅饼。使用Rect.fromCircle
使用中心和半径创建此正方形。然后在创建渐变和绘制圆弧时使用此正方形。
这是一个例子
import 'dart:math';
import 'package:flutter/material.dart';
class X1Painter extends CustomPainter {
@override
void paint(Canvas canvas, Size size) {
// create a bounding square, based on the centre and radius of the arc
Rect rect = new Rect.fromCircle(
center: new Offset(165.0, 55.0),
radius: 180.0,
);
// a fancy rainbow gradient
final Gradient gradient = new RadialGradient(
colors: <Color>[
Colors.green.withOpacity(1.0),
Colors.green.withOpacity(0.3),
Colors.yellow.withOpacity(0.2),
Colors.red.withOpacity(0.1),
Colors.red.withOpacity(0.0),
],
stops: [
0.0,
0.5,
0.7,
0.9,
1.0,
],
);
// create the Shader from the gradient and the bounding square
final Paint paint = new Paint()..shader = gradient.createShader(rect);
// and draw an arc
canvas.drawArc(rect, pi / 4, pi * 3 / 4, true, paint);
}
@override
bool shouldRepaint(X1Painter oldDelegate) {
return true;
}
}
class X1Demo extends StatelessWidget {
@override
Widget build(BuildContext context) {
return new Scaffold(
appBar: new AppBar(title: const Text('Arcs etc')),
body: new CustomPaint(
painter: new X1Painter(),
),
);
}
}
void main() {
runApp(
new MaterialApp(
theme: new ThemeData.dark(),
home: new X1Demo(),
),
);
}
我的SweepGradient版本。
完整的例子:
import 'dart:math' as math;
import 'package:flutter/material.dart';
class GradientArcPainterDemo extends StatefulWidget {
const GradientArcPainterDemo({
Key key,
}) : super(key: key);
@override
GradientArcPainterDemoState createState() => GradientArcPainterDemoState();
}
class GradientArcPainterDemoState extends State<GradientArcPainterDemo> {
double _progress = 0.9;
@override
Widget build(BuildContext context) {
return new Scaffold(
appBar: AppBar(title: const Text('GradientArcPainter Demo')),
body: GestureDetector(
onTap: () {
setState(() {
_progress += 0.1;
});
},
child: Center(
child: SizedBox(
width: 200.0,
height: 200.0,
child: CustomPaint(
painter: GradientArcPainter(
progress: _progress,
startColor: Colors.blue,
endColor: Colors.red,
width: 8.0,
),
child: Center(child: Text('$_progress')),
),
),
),
),
);
}
}
class GradientArcPainter extends CustomPainter {
const GradientArcPainter({
@required this.progress,
@required this.startColor,
@required this.endColor,
@required this.width,
}) : assert(progress != null),
assert(startColor != null),
assert(endColor != null),
assert(width != null),
super();
final double progress;
final Color startColor;
final Color endColor;
final double width;
@override
void paint(Canvas canvas, Size size) {
final rect = new Rect.fromLTWH(0.0, 0.0, size.width, size.height);
final gradient = new SweepGradient(
startAngle: 3 * math.pi / 2,
endAngle: 7 * math.pi / 2,
tileMode: TileMode.repeated,
colors: [startColor, endColor],
);
final paint = new Paint()
..shader = gradient.createShader(rect)
..strokeCap = StrokeCap.butt // StrokeCap.round is not recommended.
..style = PaintingStyle.stroke
..strokeWidth = width;
final center = new Offset(size.width / 2, size.height / 2);
final radius = math.min(size.width / 2, size.height / 2) - (width / 2);
final startAngle = -math.pi / 2;
final sweepAngle = 2 * math.pi * progress;
canvas.drawArc(new Rect.fromCircle(center: center, radius: radius),
startAngle, sweepAngle, false, paint);
}
@override
bool shouldRepaint(CustomPainter oldDelegate) => false;
}
结果: