Flutter 绘制集录 | 画个表 (上)
source link: https://mp.weixin.qq.com/s?__biz=MzI0NjU3MDA4NQ%3D%3D&%3Bmid=2247484657&%3Bidx=1&%3Bsn=f6baee00f5d2c323ea4b889e044bfe7a
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
一、本作介绍和准备
1. 效果图
如下图,通过 Flutter 的 Canvas 绘制如下的 静态
表面。
本文知识点
【1】. Flutter 中绘制旋转型的元素
【2】. Flutter 中弧线的方式
【3】. Flutter 中绘制文字的方式
【4】. Canvas.save 和 Canvas.restore 的使同。
2.资源准备
绘制文字时,可以指定文字的字体,如下在 assets/fonts
中放入对应字体。
在 pubspec.yaml
中配置后即可使用。
3.程序入口
程序入口如下,通过 ClockWidget
组件来绘制表盘。本篇 ClockWidget
只是进行静态效果展现,只需继承 StatelessWidget
即可。在 300*300
的区域内通过 ClockPainter
进行绘制。
import 'package:flutter/material.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: Scaffold(
body: Center(child: ClockWidget()),
));
}
}
class ClockWidget extends StatelessWidget {
@override
Widget build(BuildContext context) {
return CustomPaint(
size: Size(300, 300),
painter: ClockPainter(),
);
}
}
一、表盘外围绘制
1.画板的定义
这个绘制中的旋转操作很多,为了方便处理,可以将画布的中心移到画板区域的中心。这样绘制时原点就会在中心。
class ClockPainter extends CustomPainter {
Paint _paint = Paint();
@override
void paint(Canvas canvas, Size size) {
canvas.translate(size.width / 2, size.height / 2);
drawHelp(canvas,size);
}
@override
bool shouldRepaint(covariant CustomPainter oldDelegate) {
return false;
}
void drawHelp(Canvas canvas,Size size){
canvas.drawPoints(PointMode.lines, [
Offset( -size.width/2,0),Offset( size.width/2,0),
Offset( 0,-size.height/2),Offset(0,size.height/2),
], Paint());
}
}
2.绘制外圈
首先分析一下外圈的绘制,这里只要运用 绘制圆弧
和 画布旋转
。如下图,左侧是一个弧,然后通过三次旋转画布,再绘制即可的得到右图。代码如下,在每次绘制完后,将画布旋转 90°
,由于涉及局部的旋转操作,需要保存之前的画布状态,局部变换完后,恢复到之前的状态。(其实这里恰好转了360°,已复原,保不保存无所谓,但如果非 360°,如果不保存和恢复,变换将会影响之后的绘制)
void drawOuterCircle(Canvas canvas, Size size) {
final offsetAngle = 5; // 圆弧顶点和轴的夹角
_paint ..strokeWidth = 4
..color = Color(0xffD5D5D5)
..style = PaintingStyle.stroke;
canvas.save();
for (int i = 0; i < 4; i++) {
canvas.drawArc(
Rect.fromPoints(Offset(-size.width / 2, -size.height / 2),
Offset(size.width / 2, size.height / 2)),
offsetAngle * pi / 180,
pi / 2 - 2 * offsetAngle * pi / 180,
false, _paint);
canvas.rotate(pi / 2);
}
canvas.restore();
}
3.外圈格点的绘制
如下 drawDot
方法,count 变量表示格点的个数,每次遍历之后,通过 canvas.rotate(perAngle)
进行画布旋转。判断 i % 5 == 0
时绘制较粗的格线,其他的是普通格线。这就是在遍历时根据情况进行绘制的方式,在一些刻度类型的绘制中很常用。
void drawDot(Canvas canvas) {
canvas.save();
_paint
..strokeCap = StrokeCap.round
..style = PaintingStyle.fill;
double count = 60;
double perAngle = 2 * pi / count;
for (int i = 0; i < count; i++) {
if (i % 5 == 0) {
_paint
..strokeWidth = 3
..color = Colors.blue;
canvas.drawLine(Offset(120, 0), Offset(135, 0), _paint);
canvas.drawCircle(Offset(115, 0), 2, _paint..color = Colors.orange);
} else {
_paint
..strokeWidth = 1.5
..color = Colors.black;
canvas.drawLine(Offset(125, 0), Offset(135, 0), _paint);
}
canvas.rotate(perAngle);
}
canvas.restore();
}
4.绘制文字
文字通过 TextPainter
对象进行绘制,如下 _drawCircleText
方法绘制圆框中的四个文字。 _drawLogoText
绘制 CHOPS
字体的文字。这样,主要的外框就绘制完毕。
final TextPainter _textPainter = TextPainter(
textAlign: TextAlign.center, textDirection: TextDirection.ltr);
void drawText(Canvas canvas) {
_drawCircleText(canvas, 'Ⅸ', offsetX: -150);
_drawCircleText(canvas, 'Ⅲ', offsetX: 150);
_drawCircleText(canvas, 'Ⅵ', offsetY: 150);
_drawCircleText(canvas, 'Ⅻ', offsetY: -150);
_drawLogoText(canvas, offsetY: -80);
}
_drawCircleText(Canvas canvas, String text,
{double offsetX = 0, double offsetY = 0}) {
_textPainter.text = TextSpan(
text: text, style: TextStyle(fontSize: 20, color: Colors.blue));
_textPainter.layout();
_textPainter.paint(
canvas,
Offset.zero.translate(-_textPainter.size.width / 2 + offsetX,
-_textPainter.height / 2 + offsetY));
}
_drawLogoText(Canvas canvas, {double offsetX = 0, double offsetY = 0}) {
_textPainter.text = TextSpan(
text: 'Toly',
style:
TextStyle(fontSize: 30, color: Colors.blue, fontFamily: 'CHOPS'));
_textPainter.layout();
_textPainter.paint(
canvas,
Offset.zero.translate(-_textPainter.size.width / 2 + offsetX,
-_textPainter.height / 2 + offsetY));
}
三、表盘指针绘制
1.时针绘制
如下,通过 drawH(canvas, 120);
绘制120° 偏转的时针。注意,此角度是与横轴正向的夹角。
void drawH(Canvas canvas, double deg) {
canvas.save();
canvas.rotate(deg / 180 * pi);
_paint
..strokeWidth = 3
..color = Color(0xff8FC552)
..strokeCap = StrokeCap.round;
canvas.drawLine(Offset.zero, Offset(60, 0), _paint);
canvas.restore();
}
2.分针绘制
同理,如下,通过 drawM(canvas, 0);
绘制 0° 偏转的分针。
void drawM(Canvas canvas, double deg) {
canvas.save();
canvas.rotate(deg / 180 * pi);
_paint
..strokeWidth = 2
..color = Color(0xff87B953)
..strokeCap = StrokeCap.round;
canvas.drawLine(Offset.zero, Offset(80, 0, ), _paint);
canvas.restore();
}
3.秒针绘制
如下,通过 drawS(canvas, 90);
绘制 90° 偏转的秒针。
void drawS(Canvas canvas, double deg) {
_paint..strokeWidth = 2.5
..color = Color(0xff6B6B6B)
..strokeCap = StrokeCap.square
..style = PaintingStyle.stroke;
Path path = Path();
canvas.save();
canvas.rotate(deg / 180 * pi);
canvas.save();
canvas.rotate((360 - 270) / 2 / 180 * pi);
path.addArc(Rect.fromPoints(Offset(-9, -9), Offset(9, 9)), 0, 270 / 180 * pi);
canvas.drawPath(path, _paint);
canvas.restore();
_paint..strokeCap = StrokeCap.round;
canvas.drawLine(Offset(-9, 0), Offset(-20, 0), _paint);
_paint..strokeWidth = 1..color = Colors.black;
canvas.drawLine(Offset(0, 0), Offset(100, 0), _paint);
_paint..strokeWidth = 3..color = Color(0xff6B6B6B);
canvas.drawCircle(Offset.zero, 5, _paint);
_paint..color = Color(0xff8FC552)..style = PaintingStyle.fill;
canvas.drawCircle(Offset.zero, 4, _paint);
canvas.restore();
}
这里指针指示进行了简单的绘制,你可以在对应的方法中进行自己的处理。这样通过角度的设置就可以将指针进行变动,加上定时器,或者动画就可以形成动态的表面。这些处理我们在下篇进行讲述,谢谢观看 ~
Recommend
About Joyk
Aggregate valuable and interesting links.
Joyk means Joy of geeK