自定义View实战(一) 汽车速度仪表盘

2023-05-16

自定义View实战(一) 汽车速度仪表盘 


转载请以链接形式标明出处: 

http://blog.csdn.net/lxk_1993/article/details/51373269

本文出自:【lxk_1993的博客】; 


废话不说  先上效果图。


 


是不是很酷炫.

看起来觉得很难?  不难 , 其实实现起来很容易。

思路:

1.绘制一个实心的圆做仪表盘背景。 

        mPaint.setStyle(Paint.Style.FILL);
        mPaint.setColor(0xFF343434);
        canvas.drawCircle(pointX, pointY, raduis, mPaint);


2.绘制外面的两个圆环 和 里面的 两个圆环。

        //外圈2个圆
        mPaint.setStyle(Paint.Style.STROKE);
        mPaint.setColor(0xBF3F6AB5);
        mPaint.setStrokeWidth(4 * mDensityDpi);
        canvas.drawCircle(pointX, pointY, raduis, mPaint);
        mPaint.setStrokeWidth(3 * mDensityDpi);
        canvas.drawCircle(pointX, pointY, raduis - 10 * mDensityDpi, mPaint);

        //内圈2个圆
        mPaint.setStrokeWidth(5 * mDensityDpi);
        mPaint.setColor(0xE73F51B5);
        canvas.drawCircle(pointX, pointY, raduis / 2, mPaint);
        mPaint.setColor(0x7E3F51B5);
        canvas.drawCircle(pointX, pointY, raduis / 2 + 5 * mDensityDpi, mPaint);
        mPaint.setStrokeWidth(3 * mDensityDpi);


3.绘制仪表盘的刻度。

    /**
     * 绘制刻度
     */
    private void drawScale(Canvas canvas) {
        for (int i = 0; i < 60; i++) {
            if (i % 6 == 0) {
                canvas.drawLine(pointX - raduis + 10 * mDensityDpi, pointY, pointX - raduis + 50 * mDensityDpi, pointY, mPaint);
            } else {
                canvas.drawLine(pointX - raduis + 10 * mDensityDpi, pointY, pointX - raduis + 30 * mDensityDpi, pointY, mPaint);
            }
            canvas.rotate(6, pointX, pointY);
        }
    }


4.绘制仪表盘的速度标识和中间的速度 和 单位 文字。(这里有好的处理方法请留言)

    /**
     * 绘制速度标识文字
     */
    private void drawText(Canvas canvas, int value) {
        String TEXT = String.valueOf(value);
        switch (value) {
            case 0:
                // 计算Baseline绘制的起点X轴坐标
                baseX = (int) (pointX - sRaduis * Math.cos(Math.PI / 5) + textPaint.measureText(TEXT) / 2 + textScale / 2);
                // 计算Baseline绘制的Y坐标
                baseY = (int) (pointY + sRaduis * Math.sin(Math.PI / 5) + textScale / 2);
                break;
            case 30:
                baseX = (int) (pointX - raduis + 50 * mDensityDpi + textPaint.measureText(TEXT) / 2);
                baseY = (int) (pointY + textScale);
                break;
            case 60:
                baseX = (int) (pointX - sRaduis * Math.cos(Math.PI / 5) + textScale);
                baseY = (int) (pointY - sRaduis * Math.sin(Math.PI / 5) + textScale * 2);
                break;
            case 90:
                baseX = (int) (pointX - sRaduis * Math.cos(2 * Math.PI / 5) - textScale / 2);
                baseY = (int) (pointY - sRaduis * Math.sin(2 * Math.PI / 5) + 2 * textScale);
                break;
            case 120:
                baseX = (int) (pointX + sRaduis * Math.sin(Math.PI / 10) - textPaint.measureText(TEXT) / 2);
                baseY = (int) (pointY - sRaduis * Math.cos(Math.PI / 10) + 2 * textScale);
                break;
            case 150:
                baseX = (int) (pointX + sRaduis * Math.cos(Math.PI / 5) - textPaint.measureText(TEXT) - textScale / 2);
                baseY = (int) (pointY - sRaduis * Math.sin(Math.PI / 5) + textScale * 2);
                break;
            case 180:
                baseX = (int) (pointX + sRaduis - textPaint.measureText(TEXT) - textScale / 2);
                baseY = (int) (pointY + textScale);
                break;
            case 210:
                baseX = (int) (pointX + sRaduis * Math.cos(Math.PI / 5) - textPaint.measureText(TEXT) - textScale / 2);
                baseY = (int) (pointY + sRaduis * Math.sin(Math.PI / 5) - textScale / 2);
                break;

        }
        canvas.drawText(TEXT, baseX, baseY, textPaint);
    }

    /**
     * 绘制中间文字内容
     */
    private void drawCenter(Canvas canvas) {
        //速度
        textPaint.setTextSize(60 * mDensityDpi);
        float tw = textPaint.measureText(String.valueOf(speed));
        baseX = (int) (pointX - tw / 2);
        baseY = (int) (pointY + Math.abs(textPaint.descent() + textPaint.ascent()) / 4);
        canvas.drawText(String.valueOf(speed), baseX, baseY, textPaint);

        //单位
        textPaint.setTextSize(20 * mDensityDpi);
        tw = textPaint.measureText("km/h");
        baseX = (int) (pointX - tw / 2);
        baseY = (int) (pointY + raduis / 4 + Math.abs(textPaint.descent() + textPaint.ascent()) / 4);
        canvas.drawText("km/h", baseX, baseY, textPaint);
    }


5.绘制速度范围的扇形区域。

    /**
     * 绘制速度区域扇形
     */
    private void drawSpeedArea(Canvas canvas) {
        int degree;
        if (speed < 210) {
            degree = speed * 36 / 30;
        } else {
            degree = 210 * 36 / 30;
        }

        canvas.drawArc(speedRectF, 144, degree, true, speedAreaPaint);

        // TODO: 2016/5/12
        //不显示中间的内圈的扇形区域
        mPaint.setColor(0xFF343434);
        mPaint.setStyle(Paint.Style.FILL);
        canvas.drawArc(speedRectFInner, 144, degree, true, mPaint);
        mPaint.setStyle(Paint.Style.STROKE);


    }


6.实现点击让 速度动起来。实现runnable 接口。

    @Override
    public void run() {
        int speedChange;
        while (start) {
            switch (type) {
                case 1://油门
                    speedChange = 3;
                    break;
                case 2://刹车
                    speedChange = -5;
                    break;
                case 3://手刹
                    speed = 0;
                default:
                    speedChange = -1;
                    break;
            }
            speed += speedChange;
            if (speed < 1) {
                speed = 0;
            }
            try {
                Thread.sleep(50);
                setSpeed(speed);
            } catch (InterruptedException e) {
                e.printStackTrace();
                break;
            }
        }
    }


在activity中启动线程,设置监听

        //设置监听
        speedUp.setOnTouchListener(new View.OnTouchListener() {
            @Override
            public boolean onTouch(View v, MotionEvent event) {
                switch (event.getAction()) {
                    case MotionEvent.ACTION_DOWN:
                        //按下的时候加速
                        speedControlView.setType(1);
                        break;
                    case MotionEvent.ACTION_UP:
                        //松开做自然减速
                        speedControlView.setType(0);
                        break;
                }
                return true;
            }
        });
        speedDown.setOnTouchListener(new View.OnTouchListener() {
            @Override
            public boolean onTouch(View v, MotionEvent event) {
                switch (event.getAction()) {
                    case MotionEvent.ACTION_DOWN:
                        //按下的时候减速
                        speedControlView.setType(2);
                        break;
                    case MotionEvent.ACTION_UP:
                        //松开做自然减速
                        speedControlView.setType(0);
                        break;
                }
                return true;
            }
        });
        shutDown.setOnTouchListener(new View.OnTouchListener() {
            @Override
            public boolean onTouch(View v, MotionEvent event) {
                switch (event.getAction()) {
                    case MotionEvent.ACTION_DOWN:
                        //按下的时候拉手刹
                        speedControlView.setType(3);
                        break;
                    case MotionEvent.ACTION_UP:
                        //松开做自然减速
                        speedControlView.setType(0);
                        break;
                }
                return true;
            }
        });


    @Override
    protected void onResume() {
        super.onResume();
        if (speedControlView != null) {
            speedControlView.setSpeed(0);
            speedControlView.setStart(true);
        }
        new Thread(speedControlView).start();

    }


补上速度设置函数

    // 设置速度 并重绘视图
    public void setSpeed(int speed) {
        this.speed = speed;
        postInvalidate();
    }


搞定.

看,是不是很简单。

如果你喜欢我的博客,请关注我。

欢迎留言拍砖。

友情链接:如何托管你的项目到github上详细教程


源码地址:

github: https://github.com/103style/SpeedControl 觉得可以的话点下star (做了些优化)

csdn:  http://download.csdn.net/download/lxk_1993/9516516 (修改前)

http://download.csdn.net/download/lxk_1993/9518999  (修改后)

 




本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

自定义View实战(一) 汽车速度仪表盘 的相关文章

  • 在JetPack Compose中手动重构所有AndroidView

    在我的项目中 我使用 JetPack Compose 和 AndroidView 来使用 XML 视图 Composable fun MyComposable message String AndroidView factory conte
  • Linearlayout 中的背景图像

    我正在为我正在使用的线性布局的背景设置图像 我遇到的问题是标题栏下方的白色边框 如果我将背景设置为某种颜色 则不会出现白色边框 有谁知道可能是什么原因造成的 我正在动态加载一些内容 但这是 xml
  • 使用 CouchDB 视图替换 SQL 中的多个联接

    我正在为我的应用程序实现过滤功能 但在 CouchDB 上编写视图时遇到问题 在 SQL 中 这将是一个具有多个连接的语句 如何替换 CouchDB 中的多重连接 本文涵盖单连接 http www cmlenz net archives 2
  • 带有表单的基于 Django 类的视图 ListView

    主视图是一个简单的分页 ListView 我想向其中添加一个搜索表单 我认为这样的事情可以解决问题 class MyListView ListView FormView form class MySearchForm success url
  • 有没有办法在android 2.1中不使用动画来旋转按钮

    我正在寻找旋转按钮的方法 不使用动画 我不想使用动画 因为this https stackoverflow com questions 8037185 onlclick listener is not working properly 如果
  • 带有装饰器和会话的 django 类视图

    我正在尝试将一些 django 视图从基于函数的视图转换为基于类的视图 但遇到了一个小问题 我的面向对象有点弱 我认为问题是我已经不知道事情的进展情况 我有一个自定义的登录装饰器 我需要在视图上使用 所以我 首先我有这个例子中的 View
  • 如何通过单击 MainFrame 内的按钮来更改 MFC 视图

    我想通过单击窗口内的按钮来更改呈现的视图像这样 https i stack imgur com 3IA2o png 我的项目设置 我制作了一个没有文档 视图支持的 MFC 项目 SDI 我在设计器中又创建了两个视图并向它们添加了类 新的视图
  • 使用自定义视图填充 ListFragments?

    以前 我可以将布局扩展为 ListView 的自定义视图层次结构 但我不知道如何对 listFragment 执行相同的操作 假设我有一个 item list 布局 其中有一个 ImageView 和 2 个文本视图 我想将其膨胀以在我的
  • 无法使clipChildren = false属性起作用[重复]

    这个问题在这里已经有答案了 我有一个黄色的RelativeLayout含有较高的红色LinearLayout 为了使整体LinearLayout可见 我设置android clipChildren false 但这并没有按预期工作
  • MVC 在视图之间传输数据

    我刚刚开始学习 MVC 并试图了解它是如何工作的 我不想将用户发送到所有编辑 插入和列表操作的不同视图 在我的示例应用程序中 视图包含项目列表 列表下方有一个带有操作 Controller Create 的表单 用于插入新项目 但没有创建视
  • 向 Rails 中的所有活动链接添加“活动”类?

    基本上 我有很多类似这样的代码 link to t profile business path business class active if current page business path business 这不是很干 我想知道是
  • iPhone 相机访问权限?

    我想知道如何访问 iPhone 相机并实时使用它 例如 仅在相机视图上绘图 另一个相关问题 可以显示吗同时 4 个摄像机视图就像 Mac 上的 Photo Booth 一样 您可以使用 AVFoundation 来做到这一点 void in
  • 在视图上按下按键时不会调用 onKeyDown

    我有一个包含两个视图的活动 一个视图重写 onDraw 并正确处理 onTouchEvent 但是当我尝试检索第二个视图的 onKeyDown 时 它没有给我任何结果 相反 当我按下后退按钮或任何其他键盘按钮时 会调用 onKeyDown
  • 在视图内调整 SVG 图像的大小

    我有一个 FloatingActionButton 其 SVG 图像绑定到它的 src 属性 但它没有显示我需要的尺寸 如何调整它的大小以显示更大的图像 这是我的画
  • 将数据传递给视图时,node ejs 引用错误数据未在 eval 处定义

    我已经接近使用express和ejs的节点应用程序 但是当我尝试将数据从控制器传递到我的视图时 如下所示 var myData theData data res render path join dirname views index my
  • Android 自定义视图忽略 XML 中的“android:enabled”?

    我正在设置android enabled false 在自定义视图上 但它似乎对isEnabled 财产 这是一个简单的测试用例 public class TestView extends View public TestView Cont
  • 如何从 silverlight 中的视图模型从一个视图导航到另一个视图?

    我有一个 ViewModel 和两个 View 如何从 ViewModel 导航到 View2 我在某处读到我们需要使用 PRISM 在 Silverlight 中从 ViewModel 打开多个视图 PRISM 有什么替代方案吗 理想情况
  • Drupal 视图 - 自定义/修改 SQL

    我遇到了 配置文件复选框 模块的问题 该模块存储以逗号分隔的自定义配置文件字段 问题是我是否创建一个视图来按值过滤 SQL 结果最终是这样的 AND profile values profile interests value in Bus
  • 确定视图是否在屏幕上 - Android

    我对这个有点困惑 首先也是最重要的是 以下链接很有用 但是我提出了一些可见性问题 链接 检查视图可见性 https stackoverflow com questions 4628800 android how to check if a
  • Android ListView 自定义适配器 ImageButton

    这可能不是正确的方法 如果有更好的方法请告诉我 我创建了一个自定义适配器类 在我的 getView 方法中我膨胀了我想要使用的视图 public View getView int position View convertView View

随机推荐