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

里面有很多更酷的控件,欢迎Star;如果喜欢Flutter,可以加入我们哦,我们的QQ群是 :892398530

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 7
    评论
Flutter中,可以使用自定义Widget来实现自定义键盘。以下是实现自定义键盘的一般步骤: 1. 创建一个StatefulWidget,该Widget将显示自定义键盘。 2. 实现一个键盘布局。可以使用Flutter提供的各种Widget(如Container、Row、Column等)来创建键盘布局,并使用GestureDetector Widget来处理键盘按钮的点击事件。 3. 在需要使用自定义键盘的地方,使用Flutter的FocusNode来控制输入框的焦点,并将自定义键盘与输入框关联起来。 下面是一个简单的实现自定义键盘的示例代码: ```dart import 'package:flutter/material.dart'; class CustomKeyboard extends StatefulWidget { @override _CustomKeyboardState createState() => _CustomKeyboardState(); } class _CustomKeyboardState extends State<CustomKeyboard> { TextEditingController _textEditingController = TextEditingController(); @override Widget build(BuildContext context) { return Container( child: Column( children: [ TextField( controller: _textEditingController, focusNode: FocusNode(), decoration: InputDecoration( hintText: 'Input something', ), ), Row( children: [ CustomButton('1'), CustomButton('2'), CustomButton('3'), ], ), Row( children: [ CustomButton('4'), CustomButton('5'), CustomButton('6'), ], ), Row( children: [ CustomButton('7'), CustomButton('8'), CustomButton('9'), ], ), Row( children: [ CustomButton('0'), CustomButton('backspace'), ], ), ], ), ); } } class CustomButton extends StatelessWidget { final String text; CustomButton(this.text); @override Widget build(BuildContext context) { return GestureDetector( onTap: () { if (text == 'backspace') { String currentText = CustomKeyboard.of(context) .controller .text; if (currentText.isNotEmpty) { CustomKeyboard.of(context) .controller .text = currentText.substring(0, currentText.length - 1); } } else { CustomKeyboard.of(context) .controller .text += text; } }, child: Container( width: 100.0, height: 80.0, decoration: BoxDecoration( border: Border.all( color: Colors.grey, ), ), child: Center( child: Text(text), ), ), ); } } class CustomKeyboardController { final TextEditingController controller; CustomKeyboardController(this.controller); void clear() { controller.clear(); } void close() { FocusScope.of(controller.context).requestFocus(FocusNode()); } } class CustomKeyboardScope extends InheritedWidget { final CustomKeyboardController controller; CustomKeyboardScope({ Key key, @required Widget child, }) : assert(child != null), controller = CustomKeyboardController(TextEditingController()), super(key: key, child: child); static CustomKeyboardController of(BuildContext context) { return (context.dependOnInheritedWidgetOfExactType<CustomKeyboardScope>()) .controller; } @override bool updateShouldNotify(CustomKeyboardScope oldWidget) { return controller != oldWidget.controller; } } ``` 在上面的示例代码中,`CustomKeyboard` Widget是自定义键盘的主Widget,它包含了一个`TextField`和一些自定义的按钮。 `CustomButton` Widget是自定义键盘中的按键,它使用`GestureDetector`来处理按钮点击事件。 `CustomKeyboardController`是自定义键盘的控制器,用于控制输入框的文本内容。 最后,使用`CustomKeyboardScope` Widget来将`CustomKeyboardController`注入到自定义键盘中。 在需要使用自定义键盘的地方,可以使用以下代码来显示自定义键盘: ```dart CustomKeyboardScope( child: CustomKeyboard(), ); ``` 同时,需要将`CustomKeyboardController`与输入框关联起来,可以使用以下代码: ```dart TextField( controller: CustomKeyboardScope.of(context).controller.textEditingController, focusNode: FocusNode(), ); ```

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 7
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

baoolong

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值