Android自定义控件开发入门与实战(15)SurfaceView

}

SurfaceView是派生自View的。也就是说用View实现的自定义控件都可以使用SurfaceView来实现。

下面我们用SurfaceView来实现一下捕捉用户的手势轨迹的示例:

public class SurfaceGesturePath extends SurfaceView {

private void init() {

// setWillNotDraw(false);

mPaint = new Paint();

mPaint.setStyle(Paint.Style.STROKE);

mPaint.setStrokeWidth(7);

mPaint.setColor(Color.BLUE);

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();

Log.d(“Rikka”,“invalidate”);

return super.onTouchEvent(event);

}

@Override

protected void onDraw(Canvas canvas) {

super.onDraw(canvas);

canvas.drawPath(mPath, mPaint);

Log.d(“Rikka”,“onDraw”);

}

上面的代码的执行结果是一片黑屏。

为什么同样的代码,派生自View就可以画图,而SurfaceView却不行?

我们调用了上面打印的LOG,在SurfaceView上点击滑动时,发现日志如下:

在这里插入图片描述

虽然走了TouchEvent的postInvalidate()方法,但是压根就不会执行onDraw()。

这时候,我们的init()函数中有一行setWillNotDraw(false);被注释了,如果我们让它执行,会怎么样呢?

在这里插入图片描述

(2)setWillNotDraw(boolean willNotDraw)

这个函数存在在View类中,它主要用在View派生子类的初始化中,如果参数willNotDraw取true,则表示当前控件没有绘制内容。当屏幕重绘的时候,这个控件不需要绘制,所以在重绘的时候也不会调用该控件的onDraw()函数。

相反如果为false,每次重绘都要执行onDraw()。

可以看出setWillNotDraw()是一个优化策略,它让控件显式的告诉系统,在重绘重绘时,哪个控件需要重绘,哪个控件不需要重绘。这样可以大大提高重绘效率。

一般而言,对于LinearLayout、RelativeLayout而言,他们的主要功能布局其中的控件,所以它们本身是没有东西需要绘制的,所以它们的构造方法在显式的设置 setWillNotDraw(true)

之所以我们上面列子中SurfaceView一开始黑屏,不重绘,真是因为它也 默认的设置setWillNotDraw为true了

所以从这里也看出,SurfaceView的设计人员其实不想让我们通过重写onDraw()函数来绘制SurfaceView的控件函数。

(3)总结:

  • SurfaceView派生自View

  • 当SurfaceView需要使用View的onDraw()函数来重绘控件时,需要在初始化的时候执行 setWillNotDraw(false)

  • View中的所有方法都是执行在UI线程的,所以并不建议SurfaceView重写View的onDraw方法来实现自定义控件,而要使用SurfaceView特有的双缓冲机制。

2、使用缓冲Canvas绘图

之前讲了SurfaceView是自带画布的,具有双缓冲技术。这是SurfaceView建议使用的绘图方式。那么我们应该如何拿到这块自画布来绘图呢?

SurfaceHolder surfaceHolder = getHolder();

Canvas canvas1 = surfaceHolder.lockCanvas();

//绘图操作

surfaceHolder.unlockCanvasAndPost(canvas1);

我们先通过surfaceHolder.lockCanvas()函数得到SurfaceView的自带缓冲画布,并将这个画布加锁,防止它被别的线程更改。

当绘制完后,我们通过surfaceHolder.unlockCanvasAndPost(canvas)来将缓冲画布释放,并将所画的内容更新到主线程的画布上,显示的显示在屏幕上。

Q:为什么得到画布时要加锁?

A:SurfaceView的缓冲

  • 20
    点赞
  • 26
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值