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


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM