View和SurfaceView实现自定义View

概述

android系统提供了View来进行绘图处理,View可以满足大部分的绘图要求,但是在某一些时候就显得有些不足了。因为View是通过刷新来重绘视图,android系统是通过发送VSYNC信号来进行屏幕的绘制,刷新的时间间隔为16ms,如果在16ms内View没有完成重绘刷新的操作,那么用户在视觉上就会有卡顿的现象。打印日志会发现有下面的警告:"skipped 47 frames! The application may be doing too much work on its main thread"


Canvas和Paint

paint的基本用法:

Paint paint = new Paint();
paint.setAntiAlias();//设置画笔的锯齿效果
paint.setColor();//设置画笔的颜色
paint.setARGB();//设置画笔的A、R、G、B值
paint.setAlpha();//设置画笔的alpha值
paint.setTextSize();//设置字体的大小
paint.setStyle();//设置画笔的风格(空心、实心)
paint.setStrokeWidth();//设置空心边框的宽度

canvas的基本用法:

//绘制点
canvas.drawPoint(x, y, paint);
//绘制单条直线
canvas.drawLine(startX , startY , endX , endY , piant);
//绘制多条直线
float[] opts = {
        startX1 , startY1 , endX1 , endY1 ,
        ...
        startXn , startYn , endXn , endYn
};
canvas.drawLines();
//绘制矩形
canvas.drawRect(left , top , right , bottom , paint);
//绘制圆角矩形
canvas.drawRoundRect(left , top , right , bottom , radiusX , radiusY , paint);
//绘制圆
canvas.drawCircle(x , y , radius , paint);
//绘制扇形
canvas.drawArc(left , top , right , bottom , startAndle , sweepAngle , useCenter ,paint);
//绘制椭圆
canvas.drawOval(left , top , right , bottom , paint);
//绘制文本
canvas.drawText(text , x , y , paint);
//绘制路径
Path path = new Path();
path.moveTo(x , y );
path.lineTo(x , y);
canvas.drawPath(path , paint);

view和surfaceview的区别

1. View主要适用于主动更新的情况下,而SurfaceView主要适用于被动更新的情况下,例如频繁的刷新;
2. View在主线程中对画面进行刷新,而SurfaceView通常会通过一个子线程来进行页面刷新;
3. View在绘图的时候没有双缓存机制,而SurfaceView在底层已经实现了双缓存机制;

总之,如果自定义的View需要频繁的刷新,或者刷新的处理比较大,就建议使用SurfaceView。


SurfaceView的使用

这里以绘画板为例,记录手指画过的轨迹:

首先创建一个SurfaceView,并实现两个接口 ----- SurfaceHolder.Callback和Runnable

public class MySurfaceView extends SurfaceView implements SurfaceHolder.Callback,Runnable{
在构造函数里面初始化

private void init(){
    mHolder = getHolder();//初始化holder
    mHolder.addCallback(this);//注册SurfaceHolder的回调方法
    setFocusable(true);
    setFocusableInTouchMode(true);
    this.setKeepScreenOn(true);
}
实现SurfaceHolder的三个方法

/**
 * surfaceview的创建
 * @param holder
 */
@Override
public void surfaceCreated(SurfaceHolder holder) {
    mIsDrawing = true;
    new Thread(this).start();//开启线程,在子线程中绘制
}
/**
 * surfaceview的改变
 * @param holder
 */
@Override
public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
}
/**
 * surfaceview的销毁
 * @param holder
 */
@Override
public void surfaceDestroyed(SurfaceHolder holder) {
    mIsDrawing = false;
}
开始绘制界面

/**
 * 在子线程中进行绘制
 */
private Path mPath = new Path();
private Paint mPaint = new Paint();
@Override
public void run() {
    mPaint.setAntiAlias(false);//设置画笔的锯齿效果
    mPaint.setAlpha(1);//设置画笔的透明度
    mPaint.setColor(Color.RED);//设置画笔的颜色
    mPaint.setTextSize(30);
    mPaint.setStyle(Paint.Style.STROKE);//设置画笔的风格(空心、实心)
    mPaint.setStrokeWidth(2);//设置空心边框的宽度

    long start = System.currentTimeMillis();
    while (mIsDrawing){
        draw();
    }
    long end = System.currentTimeMillis();
    if((end - start) < 100){//这里间隔设置为100ms
        SystemClock.sleep(100 - (end - start));
    }
}
/**
 * 重新绘制:这个时间间隔最好能控制在50ms~100ms之间
 */
private void draw(){
    try {
        mCanvas = mHolder.lockCanvas();//得到是上次的canvas
        mCanvas.drawColor(Color.WHITE);//进行清屏操作(如果没有清屏就会保持上次的操作)
        mCanvas.drawPath(mPath, mPaint);
    }catch (Exception e){
        e.printStackTrace();
    }finally {
        if(mCanvas != null){
            mHolder.unlockCanvasAndPost(mCanvas);//对画布的内容进行提交
        }
    }
}
根据手势移动变化来记录轨迹

/**
 * 记录触摸轨迹
 * @param event
 * @return
 */
@Override
public boolean onTouchEvent(MotionEvent event) {
    int x = (int) event.getX();
    int y = (int) event.getY();
    switch (event.getAction()){
        case MotionEvent.ACTION_DOWN:
            mPath.moveTo(x, y);
            break;
        case MotionEvent.ACTION_MOVE:
            mPath.lineTo(x, y);
            break;
        case MotionEvent.ACTION_UP:
            break;
    }
    return true;
}

View的使用

这里以自定义的进度条为例说明:

先定义一个自定义的view:

public class MyView extends View {
开始绘制底框和进度

@Override
protected void onDraw(Canvas canvas) {
    //创建一个画笔
    Paint mPaint = new Paint();
    //设置底框画笔的属性
    mPaint.setAntiAlias(false);//设置画笔的锯齿效果
    mPaint.setAlpha(1);//设置画笔的透明度
    mPaint.setColor(Color.RED);//设置画笔的颜色
    mPaint.setStyle(Paint.Style.FILL);//设置画笔的风格(空心、实心)

    //绘制底层框
    canvas.drawRect(0, 100, 720, 150, mPaint);

    //设置进度画笔的属性
    mPaint.setAntiAlias(false);//设置画笔的锯齿效果
    mPaint.setAlpha(1);//设置画笔的透明度
    mPaint.setColor(Color.BLACK);//设置画笔的颜色
    mPaint.setStyle(Paint.Style.FILL);//设置画笔的风格(空心、实心)
    //绘制当前的进度
    canvas.drawRect(0, 100, progress, 150, mPaint);
}
刷新进度条

/**
     * 开启绘制更新
     */
    private int offset = 0;
    public void startDraw(){
        mHnadler.postDelayed(new Runnable() {
            @Override
            public void run() {
                offset += 5;
                Message msg = Message.obtain();
                msg.what = 0000;
                msg.obj = offset;
                mHnadler.sendMessage(msg);
                mHnadler.postDelayed(this , 500);
            }
        }, 500);
    }
    /**
     * handler收到message之后刷新进度条
     */
    public void setProgress(int progress){
        this.progress = progress;
        invalidate();//主线程刷新
//        postInvalidate();//子线程刷新
    }

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值