• Android 绘制动态图


    最近准备技能大赛,需要将从传感器中读出的数据在移动客户端以图的形式绘制出来,因为平时很少绘图,于是各种查资料,算是勉强做出来了。

    以下是大赛理论效果图(左)和实际效果图(右),真的是理想很丰满,现实很骨感啊!

        

     制作的整体思路:

    1. 创建一个继承与View类自定义类
    2. 自定义类覆盖其中的onDraw()方法
    3. 在MainActivity中invalidate()方法来调用onDraw()方法来进行图形的重绘.

    绘制一个基本表:

    (注意:代码中使用了变量)

    1、绘制矩形

         Paint paint = new Paint();
            paint.setColor(Color.BLACK);
            paint.setStyle(Paint.Style.STROKE);
            Rect chartRec = new Rect(OFFSET_LEFT, OFFSET_TOP, CHARTW + OFFSET_LEFT,
                    CHARTH + OFFSET_TOP);
            canvas.drawRect(chartRec, paint);

    2、绘制左侧数值标记

    canvas.drawText("100", OFFSET_LEFT - TEXT_OFFSET - 15, OFFSET_TOP + 5,
                    paint);
            for (int i = 9; i > 0; i--) {
                canvas.drawText("" + 10 * (10 - i), OFFSET_LEFT - TEXT_OFFSET - 15,
                        OFFSET_TOP + CHARTH / 10 * i, paint);
            }
            canvas.drawText("0", OFFSET_LEFT - TEXT_OFFSET - 10, OFFSET_TOP
                    + CHARTH, paint);

    3、绘制虚线

    DashPathEffect是PathEffect类的一个子类,可以使paint画出类似虚线的样子,并且可以任意指定虚实的排列方式。

    代码中的float数组,必须是偶数长度,且>=2,指定了多少长度的实线之后再画多少长度的空白.

    如本代码中,绘制长度2的实线,再绘制长度2的空白,再绘制长度2的实线,再绘制长度2的空白,依次重复.1是偏移量

     PathEffect effects = new DashPathEffect(new float[] { 2, 2, 2, 2 }, 1);

    这样一个基本的表格绘制完成。

    动态改变界面的方法:

    Handler handler=new Handler();
    Runnable runnable=new Runnable(){
       @Override
       public void run() {
        // TODO Auto-generated method stub
        //要做的事情
        handler.postDelayed(this, 1000);
       } 
    };

     在这里我们采用消息传递机制中Handler的postDelayed(Runnable, long) 方法做定时器,每隔一秒钟发送一次Runnable对象(该对象最后将会被封装成Message对象)执行一次子线程中的操作。

    最后,贴上所有代码:

    main.xml

    <?xml version="1.0" encoding="utf-8"?>
    <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:orientation="vertical" >
        <LinearLayout
            android:id="@+id/root"
            android:orientation = "vertical"
            android:layout_width="fill_parent"
            android:layout_height="fill_parent">
        </LinearLayout>
    
    </LinearLayout>

    MainActivity.class

    public class MainActivity extends Activity {
        private Handler handler;
        private DrawTest dtest;
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.main);
            init();
    
        }
    
        private void init() {
            LinearLayout layout = (LinearLayout) findViewById(R.id.root);
            dtest = new DrawTest(this);
            dtest.invalidate();
            layout.addView(dtest);
            handler = new Handler();
            handler.post(new Runnable() {
    
                @Override
                public void run() {
                    dtest.invalidate();
                    handler.postDelayed(this, 2000);
    
                }
            });
        }
    
    }

    DrawTest.class

    public class DrawTest extends View {
        private int CHARTH = 600;//表格的高
        private int CHARTW = 400;//表格的宽
        private int OFFSET_LEFT = 70;//距离左边界距离
        private int OFFSET_TOP = 80;//距离右边界距离
        private int TEXT_OFFSET = 20;//文本距离设置
        private int X_INTERVAL = 20;//X坐标间隔距离
        private List<Point> plist;//点集合
    
        public DrawTest(Context context) {
            super(context);
            plist = new ArrayList<Point>();
        }
        @Override
        protected void onDraw(Canvas canvas) {
            super.onDraw(canvas);
            drawTable(canvas);
            preparePoint();
            drawPoint(canvas);
        }
        /**
         * 绘制表
         * @param canvas
         */
        private void drawTable(Canvas canvas) {
            Paint paint = new Paint();
            paint.setColor(Color.BLACK);
            paint.setStyle(Paint.Style.STROKE);
            Rect chartRec = new Rect(OFFSET_LEFT, OFFSET_TOP, CHARTW + OFFSET_LEFT,
                    CHARTH + OFFSET_TOP);
            canvas.drawRect(chartRec, paint);
            Path textPath = new Path();// 选择一块区域,准备写文字“曲线图测试”
            paint.setStyle(Paint.Style.FILL);
            textPath.moveTo(200, 30);// 区域开始
            textPath.lineTo(400, 30);// 区域结束
            paint.setTextSize(20);
            paint.setAntiAlias(true);// 指定是否使用抗锯齿功能,会消耗较大资源,绘制图形速度会变慢。
            canvas.drawTextOnPath("曲线图测试", textPath, 0, 0, paint);
            // 左侧数值标记
            canvas.drawText("100", OFFSET_LEFT - TEXT_OFFSET - 15, OFFSET_TOP + 5,
                    paint);
            for (int i = 9; i > 0; i--) {
                canvas.drawText("" + 10 * (10 - i), OFFSET_LEFT - TEXT_OFFSET - 15,
                        OFFSET_TOP + CHARTH / 10 * i, paint);
            }
            canvas.drawText("0", OFFSET_LEFT - TEXT_OFFSET - 10, OFFSET_TOP
                    + CHARTH, paint);
            // 绘制虚线
            Path path = new Path();
            /**
             * PathEffect是用来控制绘制轮廓(线条)的方式。
             * DashPathEffect是PathEffect类的一个子类,可以使paint画出类似虚线的样子,并且可以任意指定虚实的排列方式.
             * 代码中的float数组,必须是偶数长度,且>=2,指定了多少长度的实线之后再画多少长度的空白.
             * 如本代码中,绘制长度2的实线,再绘制长度2的空白,再绘制长度2的实线,再绘制长度2的空白,依次重复.1是偏移量,
             */
            PathEffect effects = new DashPathEffect(new float[] { 2, 2, 2, 2 }, 1);
            paint.setStyle(Paint.Style.STROKE);
            paint.setAntiAlias(false);
            paint.setPathEffect(effects);// 用于设置绘制路径时的路径效果,如点划线。
            for (int i = 1; i < 10; i++) {
                path.moveTo(OFFSET_LEFT, OFFSET_TOP + CHARTH / 10 * i);
                path.lineTo(OFFSET_LEFT + CHARTW, OFFSET_TOP + CHARTH / 10 * i);
                canvas.drawPath(path, paint);
    
            }
            
        }
        /**
         * 准备绘制点
         */
        private void preparePoint() {
            //设置点的Y坐标为30-40
            int py = (CHARTH/10)*6+OFFSET_TOP + (int) Math.rint((Math.random() * (CHARTH/10)));
            Point p = new Point(OFFSET_LEFT + CHARTW, py);
            if (plist.size() > 21) {
                plist.remove(0);//控制点的个数
                //改变每一个点的X坐标
                for (int i = 0; i < 20; i++) {
                    if (i == 0)
                        plist.get(i).x -= (X_INTERVAL - 2);
                    else
                        plist.get(i).x -= X_INTERVAL;
                }
                plist.add(p);
            } else {
                for (int i = 0; i < plist.size() - 1; i++) {
                    plist.get(i).x -= X_INTERVAL;
                }
                plist.add(p);
            }
            
        }
        /**
         * 绘制点
         * 
         * @param canvas
         */
        private void drawPoint(Canvas canvas) {
            
            Paint paint = new Paint();
            paint.setColor(Color.BLACK);
            paint.setStrokeWidth(3);// 设置笔触的宽度
            if (plist.size() >= 2) {
                for (int i = 0; i < plist.size() - 1; i++) {
                    canvas.drawPoint(plist.get(i).x, plist.get(i).y, paint);
                }
            }
        }
    }

     【注:invalidate ()和postInvalidate()方法的选择:文档中已经写的很清楚了,如果要使用invalidate()必须要在UI主线程当中,如果不在UI主线程中,就要去调用postInValidate()】

    如果大家有什么更好的方法或该文中有什么不足,希望大家指点。

    Demo下载http://download.csdn.net/detail/af74776/7440807

  • 相关阅读:
    vuerouter 无登录页根据权限动态添加菜单栏
    [转]Pytorch常用代码块
    colab查看gpu信息
    文本预处理
    swagger
    springboot中使用分页插件
    sqlServer数据库创建定时任务方法
    java查询的数据返回给jsp页面,通过jstl来获取后端页面数据,并显示数据
    EF Core 生成实体类
    .net core 部署无法正常跨域访问的解决方案
  • 原文地址:https://www.cnblogs.com/scetopcsa/p/3765719.html
Copyright © 2020-2023  润新知