Android屏幕刷新一遍时间间隔为16ms,如果view能够在16ms内完成所需要执行的绘图换作,那么在视觉上,界面就是流畅的,否则就会出现卡顿现象,在很多情况下,这些逻辑处理又是必须的,为了解决这个问题,Android 引用了surfaceView,在二个方面改进了View的绘图操作:
使用双缓冲技术
自带画布,支持在子线程中更新画布内容
view和surfaceView使用场景:
当界面需要被动更新时,用view较好,比如,与手势交互的场景,因为画面的更新是依赖ontouch来完成,所以可以直接使用invalidate函数,在这种一次touch和下一次touch时间长的话,就不会产生影响
当界面需要主动刷新,使用surfaceView比较好,比如视频播放摄像头等
基本用法:
surfaceView派生View
package com.loaderman.customviewdemo; import android.content.Context; import android.graphics.Canvas; import android.graphics.Color; import android.graphics.Paint; import android.graphics.Path; import android.util.AttributeSet; import android.view.MotionEvent; import android.view.SurfaceView; public class ViewGesturePath extends SurfaceView { private Paint mPaint; private Path mPath; public ViewGesturePath(Context context) { super(context); init(); } public ViewGesturePath(Context context, AttributeSet attrs) { super(context, attrs); init(); } public ViewGesturePath(Context context, AttributeSet attrs, int defStyle) { super(context, attrs, defStyle); init(); } private void init(){ setWillNotDraw(false); mPaint = new Paint(); mPaint.setStyle(Paint.Style.STROKE); mPaint.setStrokeWidth(5); mPaint.setColor(Color.RED); mPath = new Path(); } @Override public boolean onTouchEvent(MotionEvent event) { int x = (int)event.getX(); int y = (int)event.getY(); if (event.getAction() == MotionEvent.ACTION_DOWN){ mPath.moveTo(x,y); return true; }else if (event.getAction() == MotionEvent.ACTION_MOVE){ mPath.lineTo(x,y); } postInvalidate(); return super.onTouchEvent(event); } @Override protected void onDraw(Canvas canvas) { super.onDraw(canvas); canvas.drawPath(mPath,mPaint); } }
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:orientation="vertical" android:background="#ffffff" android:layout_width="fill_parent" android:layout_height="fill_parent"> <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:textColor="@android:color/holo_red_dark" android:text="捕捉手势轨迹,画吧,少年"/> <com.loaderman.customviewdemo.ViewGesturePath android:layout_width="match_parent" android:layout_height="match_parent"/> </LinearLayout>
效果:
正确用法:
package com.loaderman.customviewdemo; import android.content.Context; import android.graphics.Canvas; import android.graphics.Color; import android.graphics.Paint; import android.graphics.Path; import android.util.AttributeSet; import android.view.MotionEvent; import android.view.SurfaceHolder; import android.view.SurfaceView; public class SurfaceViewGesturePath extends SurfaceView { private Paint mPaint; private Path mPath; public SurfaceViewGesturePath(Context context) { super(context); init(); } public SurfaceViewGesturePath(Context context, AttributeSet attrs) { super(context, attrs); init(); } public SurfaceViewGesturePath(Context context, AttributeSet attrs, int defStyle) { super(context, attrs, defStyle); init(); } private void init() { mPaint = new Paint(); mPaint.setStyle(Paint.Style.STROKE); mPaint.setStrokeWidth(5); mPaint.setColor(Color.RED); mPath = new Path(); } @Override public boolean onTouchEvent(MotionEvent event) { int x = (int) event.getX(); int y = (int) event.getY(); if (event.getAction() == MotionEvent.ACTION_DOWN) { mPath.moveTo(x, y); return true; } else if (event.getAction() == MotionEvent.ACTION_MOVE) { mPath.lineTo(x, y); } drawCanvas(); return super.onTouchEvent(event); } private void drawCanvas() { new Thread(new Runnable() { @Override public void run() { SurfaceHolder surfaceHolder = getHolder(); Canvas canvas = surfaceHolder.lockCanvas();//使用缓冲Canvas绘图 canvas.drawPath(mPath, mPaint); surfaceHolder.unlockCanvasAndPost(canvas); } }).start(); } }
效果同上