今天对汽车仪表盘的代码进行了优化,刚刚测试过,性能还是不错的,因为没有多余的动作和控件啦;我先放一张图(以前的图片,现在的更好);温馨提示:仪表盘设置了可通过手指触摸加速,抬起手减速的效果
上面的效果是Canvas画出来的,绘制的原理和安卓原生的差不多啦,为了提高效率,我将底部的表格和指针预先画成图片,这样每次 绘制图片 比 绘制Path和Line 快多了;
第一步:我们先看看怎么绘制底图的表格的。
要绘制表格,要先算出表格之间的偏移角度,这个可以根据需要个性计算哈;然后表格我们分2部分画,即速度大于120的是一部分,小于120的分另一部分画;怎么画呢?我们就画竖线即可,有人说140的速度可不是竖线呀?这个简单,不是竖线我们旋转下画布,旋转到让140速度的那个刻度垂直于水平面,我们再画竖线,其他速度的刻度都是一个道理,都是先旋转到该刻度垂直于水平面;好了原理知道了,我们就开始动手吧,下面是我的代码
class DashBoardTablePainter {
final double tableSpace;
var speedTexts=["0","20","40","60","80","100","120","140","160","180","200","230","260"];
final Size size;
final PictureRecorder _recorder = PictureRecorder();
DashBoardTablePainter(this.tableSpace,this.size);
Picture getBackGround() {
Canvas canvas=Canvas(_recorder);
canvas.clipRect(new Rect.fromLTWH(0.0, 0.0, size.width, size.height));
drawTable( canvas, size);
return _recorder.endRecording();
}
///画仪表盘的表格
void drawTable(Canvas canvas, Size size){
canvas.save();
double halfWidth=size.width/2;
double halfHeight=size.height/2;
canvas.translate(halfWidth, halfHeight);
Paint paintMain=new Paint();
paintMain.color=Colors.blue;
paintMain.strokeWidth=2.5;
paintMain.style=PaintingStyle.fill;
Paint paintOther=new Paint();
paintOther.color=Colors.blue;
paintOther.strokeWidth=1;
paintOther.style=PaintingStyle.fill;
drawLongLine(canvas,paintMain,halfHeight,speedTexts[6]);
canvas.save();
for(int i=61;i<=120;i++){
canvas.rotate(tableSpace);
if(i%10==0){
int a=(i/10).ceil();
changePaintColors(paintMain,i);
drawLongLine(canvas,paintMain,halfHeight,speedTexts[a]);
}else if(i%5==0){
changePaintColors(paintMain,i);
drawMiddleLine(canvas,paintMain,halfHeight);
}else{
changePaintColors(paintOther,i);
drawSmallLine(canvas,paintOther,halfHeight);
}
}
canvas.restore();
canvas.save();
for(int i=59;i>=0;i--){
canvas.rotate(-tableSpace);
if(i%10==0){
int a=(i/10).ceil();
changePaintColors(paintMain,i);
drawLongLine(canvas,paintMain,halfHeight,speedTexts[a]);
}else if(i%5==0){
changePaintColors(paintMain,i);
drawMiddleLine(canvas,paintMain,halfHeight);
}else{
changePaintColors(paintOther,i);
drawSmallLine(canvas,paintOther,halfHeight);
}
}
canvas.restore();
canvas.restore();
}
void changePaintColors(Paint paint,int value){
if(value<=20){
paint.color=Colors.green;
}else if(value<80){
paint.color=Colors.blue;
}else{
paint.color=Colors.red;
}
}
///画仪表盘上的长线
void drawLongLine(Canvas canvas,Paint paintMain,double halfHeight,String text){
canvas.drawLine(new Offset(0.0, -halfHeight), new Offset(0.0, -halfHeight+15), paintMain);
TextPainter textPainter = new TextPainter();
textPainter.textDirection = TextDirection.ltr;
textPainter.text = new TextSpan(text: text, style: new TextStyle(color:paintMain.color,fontSize: 15.5,));
textPainter.layout();
double textStarPositionX = -textPainter.size.width / 2;
double textStarPositionY = -halfHeight+19;
textPainter.paint(canvas, new Offset(textStarPositionX, textStarPositionY));
}
void drawMiddleLine(Canvas canvas,Paint paintMain,double halfHeight){
canvas.drawLine(new Offset(0.0, -halfHeight), new Offset(0.0, -halfHeight+10), paintMain);
}
///画短线
void drawSmallLine(Canvas canvas,Paint paintOther,double halfHeight){
canvas.drawLine(new Offset(0.0, -halfHeight), new Offset(0.0, -halfHeight+7), paintOther);
}
}
第二步:绘制指针。
指针这玩意也可以根据需要随便自定义大小,颜色,形状等,我的指针是Path绘制的,你们也可以不用代码写,直接找个图片代替也是没问题的哈,(补充下,上面讲的表格其实也是可以通过图片代替的,不过不能绘制特效哦)这个几乎没啥难度哈,我们看下代码
class IndicatorPainter {
final PictureRecorder _recorder = PictureRecorder();
final Size size;
IndicatorPainter(this.size);
///画速度指针
Picture drawIndicator(){
Canvas canvas=Canvas(_recorder);
canvas.clipRect(new Rect.fromLTWH(0.0, 0.0, size.width, size.height));
double halfHeight=size.height/2;
double halfWidth=size.width/2;
Path path=new Path();
path.moveTo(-2.5, 20);
path.lineTo(2.5, 20);
path.lineTo(6.0, -30);
path.lineTo(0.5, -halfHeight+8);
path.lineTo(-0.5, -halfHeight+8);
path.lineTo(-6.0, -30);
path.close();
canvas.save();
canvas.translate(halfWidth, halfHeight);
Paint paint=new Paint();
paint.color=Colors.red;
paint.style=PaintingStyle.fill;
canvas.drawPath(path, paint);
paint.color=Colors.black;
canvas.drawCircle(new Offset(0.0,0.0), 6, paint);
canvas.restore();
return _recorder.endRecording();
}
}
第三步:将底图,指针,还有速度值叠加绘制
底图,指针都画出来了,那还有啥难度呢,就只剩根据需要将指针旋转绘制,将速度值绘制在表盘上;另外唠叨几句,曾想过将底图的表格单独弄个控件,这样就省去每次绘制底图的麻烦,但是有的人想在速度高时表盘渲染成红色,速度低时渲染成绿色,所以想想还是把底图每次都绘制下吧;好了,看代码
class DashBoardState extends State<DashBoard>{
final platform = const MethodChannel('com.flutter.lgyw/sensor');
bool _isGetPressure=false;
int pressures=0;final double wholeCirclesRadian=6.283185307179586;
///虽然一个圆被分割为160份,但是只显示120份
final int tableCount=160;
Size dashBoardSize;
double tableSpace;
Picture _pictureBackGround;
Picture _pictureIndicator;
@override
void initState() {
super.initState();
dashBoardSize=new Size(300.0,300.0);
tableSpace=wholeCirclesRadian/tableCount;
_pictureBackGround=DashBoardTablePainter(tableSpace,dashBoardSize).getBackGround();
_pictureIndicator=IndicatorPainter(dashBoardSize).drawIndicator();
}
@override
Widget build(BuildContext context) {
return new Scaffold(
appBar: new AppBar(
title: new Text("汽车仪表盘"),
),
body: new Center(
child:GestureDetector(
onPanDown:(DragDownDetails dragDownDetails){
_isGetPressure=true;
boostSpeed();
},
onPanCancel: (){
handleEndEvent();
},
onPanEnd: (DragEndDetails dragEndDetails){
handleEndEvent();
},
child:new CustomPaint(
size: dashBoardSize,
painter: new DashBoardIndicatorPainter(pressures,tableSpace,_pictureBackGround,_pictureIndicator),
),
),
),
);
}
void boostSpeed() async {
while (_isGetPressure){
if(pressures<120){
setState(() {
pressures++;
});
}
await Future.delayed(new Duration(milliseconds: 30));
}
}
void handleEndEvent(){
_isGetPressure=false;
bringDownSpeed();
}
void bringDownSpeed() async {
while (!_isGetPressure){
setState(() {
pressures--;
});
if(pressures<=0){
break;
}
await Future.delayed(new Duration(milliseconds: 30));
}
}
}
到这里,仪表盘控件就完成了,你只需要将它加到你需要的地方;是不是很简单哈,
如果在使用的过程中有什么问题,请留言,随时为你解答,
最后附上源码地址:https://github.com/OpenFlutter/PullToRefresh;
————————————————
版权声明:本文为CSDN博主「baoolong」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/baoolong/article/details/86488127