1.背景介紹
最近項目要繪制股票走勢圖,並繪制能夠跟隨手指滑動的指示線(Indicator)來精確查看股票價格和日期。如下圖所示:
上圖中的那條白色直線就是股票的指示線,用來跟隨手指精確確定股票的時間和股票價格。不論是繪制股票圖還是繪制指示線,我們首先想到的就是用Android中的自定義View來實現。實踐證明,使用View能夠很好地實現靜態的圖片,但是對用動態圖像的繪制,往往會出現延遲的現象。就如上圖的指示線,實際用View類實現的,跟隨手指移動時,指示線就會出現延遲的現象,嚴重影響了用戶體驗,這里自然而然的要用到SurfaceView以提高性能,提高滑動的流暢度。
2.Android中View和SurfaceView對比
下面例舉了一下二者的區別:
View SurfaceView
只能在UI主線程中更新畫面 UI主線程和新起的獨立線程中都可更新畫面
無雙緩沖機制 采用雙緩沖機制,速度快
還有其他區別希望大家補充。
3.案例
下面是該程序實現的主要代碼,隱去了數據的填充。
package com.devin; import android.content.Context; import android.graphics.Canvas; import android.graphics.Color; import android.graphics.Paint; import android.graphics.PixelFormat; import android.graphics.PorterDuff.Mode; import android.view.MotionEvent; import android.view.SurfaceHolder; import android.view.SurfaceHolder.Callback; import android.view.SurfaceView; public class MyStockIndicatorView extends SurfaceView implements Callback { private SurfaceHolder surfaceHolder; private Paint paint; private float currentX; public MyStockIndicatorView(Context context) { super(context); // 初始化SurfaceHolder surfaceHolder = this.getHolder(); surfaceHolder.addCallback(this); // 讓整個界面透明 surfaceHolder.setFormat(PixelFormat.TRANSPARENT); setZOrderOnTop(true);
//初始化畫筆 paint = new Paint(); paint.setAntiAlias(true); paint.setColor(Color.WHITE);
//設置界面可以點擊 setFocusable(true); }
//觸屏事件,每次響應事件后改變坐標值,然后重新繪制 public boolean onTouchEvent(MotionEvent event) { int eventaction = event.getAction(); int x = (int) event.getX(); switch (eventaction) { case MotionEvent.ACTION_DOWN: currentX = x; paintIndicator(); break; case MotionEvent.ACTION_UP: clearCavas(); break; case MotionEvent.ACTION_MOVE: currentX; paintIndicator(); break; case MotionEvent.ACTION_CANCEL: clearCavas(); break; } return true; }
//畫直線 private void paintIndicator() { Canvas canvas = surfaceHolder.lockCanvas();
//下面兩句用來改變原點、同時把默認的坐標系轉換成笛卡爾坐標系 //canvas.translate(chartLeft, getHeight()); //canvas.scale(1, -1); canvas.drawLine(currentX, 0, currentX, getHeight(), paint); surfaceHolder.unlockCanvasAndPost(canvas); }
//清屏 private void clearCavas() {
//每次繪制前要鎖定畫布 Canvas canvas = surfaceHolder.lockCanvas(); canvas.drawColor(Color.TRANSPARENT, Mode.CLEAR);
//繪制完成后解鎖畫布 surfaceHolder.unlockCanvasAndPost(canvas); } public void surfaceChanged(SurfaceHolder surfaceHolder, int format, int width, int height) { } public void surfaceCreated(SurfaceHolder surfaceHolder) {
//在此處初始化數據 initData(); } public void surfaceDestroyed(SurfaceHolder holder) { } }
上述代碼關鍵地方都有注釋。對於SurfaceView的實現,需要繼承SurfaceView和實現Callback接口,同時需要實現三個方法:surfaceCreated、surfaceDestroyed、surfaceChanged方法,分別表示SurfaceView創建、銷毀、界面改變時執行的方法。在構造函數中要初始化SurfaceHolder,同時每次繪圖前要鎖定畫布,繪制完成后解鎖畫布。
歡迎關注公眾號"Devin說",會不定期更新技術知識