Flutter汽车仪表盘DashBoard

今天对汽车仪表盘的代码进行了优化,刚刚测试过,性能还是不错的,因为没有多余的动作和控件啦;我先放一张图(以前的图片,现在的更好);温馨提示:仪表盘设置了可通过手指触摸加速,抬起手减速的效果

上面的效果是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

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值