自定义View一:绘制-Canvas

1、概念

画布,通过画笔绘制几何图形、文本、路径和位图等。

2、常用API

常用API分为绘制、变换、状态保存和恢复

2.1 绘制颜色

1.	canvas.drawColor(Color.GREEN);    

2.2 绘制集合图形

//绘制点  
float[] pts = {200, 300, 200, 400, 200, 500};  
canvas.drawPoints(pts, mPaint);  
//绘制线  
canvas.drawLine(200, 200, 200, 400, mPaint);  
//绘制矩形  
RectF rect = new RectF(100, 100, 400, 400);  
canvas.drawRect(rect, mPaint);  
//绘制圆角矩形  
canvas.drawRoundRect(rect, 20, 20, mPaint);  
//绘制圆  
canvas.drawCircle(200, 200, 100, mPaint);  
//绘制椭圆  
canvas.drawOval(rect, mPaint);  
//绘制圆弧  
canvas.drawArc(rect, -180, 180, true, mPaint); 

2.3 绘制文本

canvas.drawText(text, 50, 50, mPaint);  
Path path = new Path();  
path.addArc(100, 100, 300, 300, -180, 360);  
canvas.drawPath(path, mPaint);  
canvas.drawTextOnPath(text, path, 10, -10, mPaint);  

2.4 绘制位图

canvas.drawBitmap(bitmap, 0, 0, mPaint);  
	  
Matrix matrix = new Matrix();  
matrix.postRotate(45);  
matrix.postTranslate(400, 0);  
canvas.drawBitmap(bitmap, matrix, mPaint);  
	  
Rect src = new Rect(0, 0, 100, 200);  
Rect dst = new Rect(600, 0, 700, 200);  
canvas.drawBitmap(bitmap, src, dst, mPaint);  

2.5 绘制路径

Path path = new Path();  
path.moveTo(0,0);  
path.lineTo(100,100);  
path.lineTo(300,200);  
canvas.drawPath(path, mPaint);  

2.6 变换

//平移  
canvas.translate(100, 100);  
//旋转  
canvas.rotate(45);  
canvas.rotate(45, 100,100);  
//缩放  
canvas.scale(0.5f, 0.5f);  
canvas.scale(0.5f, 0.5f, 100,100);  
//错切  
canvas.skew(0.1f, 0.5f);  

2.6.1 rotate

可以叠加,而且这里实际上移动的是坐标,画布的位置并没有变,也就是说坐标原点变到了原来(100100)的位置。

注意rotate(float degrees, float px, float py)

canvas.rotate(45, 100, 100);  

源码:

/** 
 * Preconcat the current matrix with the specified rotation. 
 * 
 * @param degrees The amount to rotate, in degrees 
 * @param px The x-coord for the pivot point (unchanged by the rotation) 
 * @param py The y-coord for the pivot point (unchanged by the rotation) 
 */  
public final void rotate(float degrees, float px, float py) {  
    if (degrees == 0.0f) return;  
	translate(px, py);  
	rotate(degrees);  
	translate(-px, -py);  
} 

根据源码可以很明显的看到,其实就是先平移到指定位置,在指定位置进行了旋转之后又对画布做了返回平移处理,这样就实现了以自定义点为中心旋转画布的效果。

2.6.2 scale

scale(float sx, float sy, float px, float py);

源码:

/** 
 * Preconcat the current matrix with the specified scale. 
 * 
 * @param sx The amount to scale in X 
 * @param sy The amount to scale in Y 
 * @param px The x-coord for the pivot point (unchanged by the scale) 
 * @param py The y-coord for the pivot point (unchanged by the scale) 
 */  
public final void scale(float sx, float sy, float px, float py) {  
    if (sx == 1.0f && sy == 1.0f) return;  
    translate(px, py);  
    scale(sx, sy);  
    translate(-px, -py);  
} 

 同理,也是先实现平移,在指定位置缩放之后又对画布做了返回平移处理,从而实现了以自定义点为中心缩放画布的效果。

2.6.3 skew

/** 
 * @params sx 将画布在x方向上倾斜相应的角度,sx倾斜角度的tan值,其实就是将y逆时针旋转相应的角度 
 * @params sy 将画布在y方向上倾斜相应的角度,sx倾斜角度的tan值,其实就是将x顺时针旋转相应的角度 
 * 
 * 水平错切 
 */  
canvas.skew(1, 0);  
canvas.drawRect(rect, mPaint);   

     

对于点p(x0, y0),错切skew(sx,sy)后坐标(x,y),经过下面的转换:

x=x0 + sx*y0

y=y0 + sy*x0

当sx=1时,即将画布在x方向上旋转45度,其实就是x轴保持方向不变,y轴逆时针旋转45度。

当sy=1时,即将画布在y方向上旋转45度,其实就是y轴保持方向不变,x轴顺时针旋转45度。

3、状态保存与恢复

3.1 saveFlags

3.2 save

//画布状态保存与恢复,  
int layerId = canvas.save();  
canvas.restore();  
canvas.restoreToCount(layerId);  

3.3 saveLayer

关键方法:

//新建图层  
public int saveLayer(float left, float top, float right, float bottom, Paint paint, int saveFlags)  
//切换到指定图层的上一级图层  
public void restoreToCount(int saveCount) {  
//获取图层数量  
public int getSaveCount()  

代码:

canvas.saveLayer(0, 0, 200, 200, mPaint);  
canvas.saveLayerAlpha(0, 0, 200, 200, 100);  
canvas.restore();  
canvas.restore();

4、应用

4.1 时钟

重写onDraw方法:

@Override  
protected void onDraw(Canvas canvas) {  
    super.onDraw(canvas);  
    // 绘制时间  
    drawTime(canvas);  
    // 绘制刻度盘  
    drawPanel(canvas);  
}

   绘制刻度盘:

for (int i = 1; i <= 60; i++) {  
    canvas.save();  
    canvas.rotate(360 / 60 * i, mWidth / 2, mHeight / 2);  
    canvas.translate(mWidth / 2, 0);  
    if (i % 5 == 0) {  
        canvas.drawLine(0, 0, 0, 30, mPaint);  
        //显示数字  
        String text = i / 5 + "";  
        //获取数字的宽度  
        mPaint.getTextBounds(text, 0, text.length(), mRect);  
        canvas.drawText(text, (0 - mRect.width()) / 2, 40 + mRect.height(), mPaint);  
    } else {  
        canvas.drawLine(0, 0, 0, 15, mPaint);  
    }  
    canvas.restore();  
} 

   绘制时间:

//时针  
canvas.save();  
canvas.rotate(360 * mHour / 12, mWidth / 2, mHeight / 2);  
canvas.drawLine(mWidth / 2, mHeight / 2, mWidth / 2, 160, mPaint);  
canvas.restore();  
  
//分钟  
canvas.save();  
canvas.rotate(360 * mMinutes / 60, mWidth / 2, mHeight / 2);  
canvas.drawLine(mWidth / 2, mHeight / 2, mWidth / 2, 140, mPaint);  
canvas.restore();  
  
//秒针  
canvas.save();  
canvas.rotate(360 * mSeconds / 60, mWidth / 2, mHeight / 2);  
canvas.drawLine(mWidth / 2, mHeight / 2, mWidth / 2, 100, mPaint);  
canvas.restore(); 

4.2 刮刮乐

初始化画笔:

mPaint = new Paint();  
mPaint.setColor(Color.GRAY);  
	  
mPathPaint = new Paint();  
mPathPaint.setColor(Color.GRAY);  
mPathPaint.setStrokeWidth(30);  
mPathPaint.setStyle(Paint.Style.FILL);  
mPathPaint.setStrokeJoin(Paint.Join.ROUND);  
//采用XOR绘制,擦除灰色蒙层,从而显示出底部奖品图  
mPathPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.XOR)); 

绘制:

@Override  
protected void onDraw(Canvas canvas) {  
    super.onDraw(canvas);  
  
    //绘制奖品结果图  
    canvas.drawBitmap(mBitmap,  
            (mWidth - mBitmap.getWidth()) / 2,  
            (mHeight - mBitmap.getHeight()) / 2, mPaint);  
    //绘制灰色蒙层  
    canvas.drawBitmap(mGrayBm, 0, 0, mPaint);  
	  
    mGrayCanvas.drawRect(0, 0, mWidth, mHeight, mPaint);  
    mGrayCanvas.drawPath(mPath, mPathPaint);  
}  

滑动事件处理:

private float mMoveX, mMoveY;  
@Override  
public boolean onTouchEvent(MotionEvent event) {  
    mMoveX = event.getX();  
    mMoveY = event.getY();  
    switch (event.getAction()) {  
        case MotionEvent.ACTION_DOWN:  
            mPath.moveTo(mMoveX, mMoveY);  
            invalidate();  
            return true;  
        case MotionEvent.ACTION_MOVE:  
            float endX = event.getX();  
            float endY = event.getY();  
            mPath.quadTo((endX - mMoveX) / 2 + mMoveX,   
                    (endY - mMoveY) / 2 + mMoveY, endX, endY);  
            invalidate();  
            return true;  
    }  
    return super.onTouchEvent(event);  
}  

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值