研究过一段时间自定义视图,下面我们来实现一个比较常见的功能----闹钟。
废话不多说,先上效果图:
从上图可以看见,帆布作为底层画布,我们需要画一个大钟圆圈,画俩条直线作为指针,问题是俩个铃铛怎么画?
这里我们可以用到俩种方法:
1.图层覆盖
2. PorterDuffXfermode混合模式
针对上面的思路我们给出相应的代码:
1.使用图层覆盖
公共类AlarmClock的扩展视图{
私人涂料粉刷;
私人路径路径;
公众的AlarmClock(上下文的背景下,ATTRS的AttributeSet,诠释defStyleAttr){
超(背景下,ATTRS,defStyleAttr);
在里面();
}
公众的AlarmClock(上下文的背景下,ATTRS的AttributeSet){
超(背景下,ATTRS);
在里面();
}
公众的AlarmClock(上下文的背景下){
超级(上下文);
在里面();
}
私人无效的init(){
油漆=新的油漆();
paint.setColor(Color.WHITE);
paint.setStyle(Style.FILL);
paint.setAntiAlias(真);
paint.setStrokeWidth(30);
}
@覆盖
保护无效的onDraw(帆布油画){
super.onDraw(画布);
// 1.画出左右俩个圆
canvas.drawColor(Color.RED);
canvas.drawCircle(200,100,100,油漆);
canvas.drawCircle(500,100,100,油漆);
canvas.save();
// INT SC = canvas.saveLayer(0,0,600,800,空,canvas.ALL_SAVE_FLAG);
// 2.画出红色圆乙
paint.setColor(Color.RED);
canvas.drawCircle(350,300,270,油漆);
canvas.save();
// 3.再画出底下一个大圆Ç
paint.setColor(Color.WHITE);
canvas.drawCircle(350,300,250,油漆);
canvas.save();
// 4.在画出红色小圆ð
paint.setColor(Color.RED);
canvas.drawCircle(350,300,200,油漆);
canvas.save();
// 5.在小圆上画出直线路径
paint.setColor(Color.WHITE);
浮动[] PTS = {350,150,350,300};
浮[] PTS1 = {335,300,500,300};
canvas.drawLines(PTS,油漆);
canvas.drawLines(PTS1,油漆);
canvas.save();
canvas.restore();
}
}
上面使用方法比较简单,代码直观,我们不细说了。看第二种方式
2.使用PorterDuffXfermode混合模式
公共类AlarmClock的扩展视图{
私人诠释宽度= 400,高度= 400; //定义绘图区域
私人位图srcBitmap,dstBitmap;
私人涂料mPaint;
私人诠释的centerX,centerY; //中心点
私人诠释largerRadius,smallRadius; //大小圆的半径
私有静态最终诠释DISTANCE_X = 40,DISTANCE_Y = 60; //设置绘制线条的长度
私人INT strokeWidth = 16;
公众的AlarmClock(上下文的背景下){
超级(上下文);
在里面();
}
公众的AlarmClock(上下文的背景下,ATTRS的AttributeSet){
超(背景下,ATTRS);
在里面();
}
公众的AlarmClock(上下文的背景下,ATTRS的AttributeSet,诠释defStyleAttr){
超(背景下,ATTRS,defStyleAttr);
在里面();
}
私人无效的init(){
的centerX =宽度/ 2;
centerY =身高/ 2;
largerRadius =宽/ 4;
smallRadius =宽/ 8;
mPaint =新的油漆();
srcBitmap = creatBitMapSrc();
dstBitmap = creatBitMapDst();
}
@覆盖
保护无效的onDraw(帆布油画){
super.onDraw(画布);
canvas.drawBitmap(srcBitmap,0,0,mPaint); //首先绘制的Src图,做为底图,因为在使用XOR模式后,源所在区域会被截取,使用SRC_OUT同样可以实现
INT layerId的= canvas.saveLayer(0,0,宽* 2,身高* 2,mPaint,Canvas.ALL_SAVE_FLAG); //创建新的图层
canvas.drawBitmap(srcBitmap,0,0,mPaint);
mPaint.setXfermode(新PorterDuffXfermode(PorterDuff.Mode.SRC_OUT));
canvas.drawBitmap(dstBitmap,0,0,mPaint);
mPaint.setXfermode(NULL);
canvas.restoreToCount(layerId的);
}
/ **
*创建源图
* @返回
* /
私人位图creatBitMapSrc(){
位图的位图= Bitmap.createBitmap(宽度,高度,Bitmap.Config.ARGB_8888);
帆布C =新的Canvas(位图);
涂料mPaint =新的油漆();
mPaint.setColor(0xffffcc22);
c.drawCircle(的centerX,centerY,largerRadius + 20,mPaint); //首先以背景色填充画圆
// c.drawOval(新RectF(80,80,宽度80,高度80),mPaint);
mPaint.setColor(为0xffffffff);
mPaint.setStyle(Paint.Style.STROKE);
mPaint.setStrokeWidth(strokeWidth);
c.drawCircle(的centerX,centerY,largerRadius,mPaint); //绘制一个无填充的圆,半径比填充的圆小一些
// c.drawOval(新RectF(100,100,宽度100,高度100),mPaint); //以矩形区域画椭圆,同样可以实现,效果一样
c.drawLine(的centerX,centerY,的centerX + DISTANCE_X,centerY,mPaint); //绘制横向距离为40的线条
c.drawLine(的centerX,centerY + strokeWidth / 2的centerX,centerY-DISTANCE_Y,mPaint); //因为画笔宽度为strokeWidth,偏移strokeWidth / 2,让两条直线完全重合纵向为60
返回位图;
}
/ **
*创建目标图
* @返回
* /
私人位图creatBitMapDst(){
位图的位图= Bitmap.createBitmap(宽度,高度,Bitmap.Config.ARGB_8888);
帆布C =新的Canvas(位图);
涂料mPaint =新的油漆();
c.drawColor(0xffffcc22);
mPaint.setColor(为0xffffffff);
/ **
*双重罪(双D)
*双COS(双D)
*双谭(双D)在数学中这三个方法传进去的数值不是度数,而是
*度数所对应的弧度值计算弧度值的方法有:
*
* 1。使用数学类里面的toRadians()方法
* Math.toRadians()根据度数取得相对应的弧度值
*
* 2.Math.PI代表180度所对应的弧度值,所以计算某个角度所对应的弧度值可以使用公式:
*弧度值=角度值* Math.PI / 180
* /
INT X1 =(int)的(的centerX - 100 * Math.sin(Math.toRadians(45)));
INT Y1 =(int)的(centerY - 100 * Math.cos(45 * Math.PI / 180));
INT X2 =(int)的(的centerX + 100 * Math.sin(Math.toRadians(45)));
INT Y2 =(int)的(centerY - 100 * Math.cos(Math.toRadians(45)));
c.drawCircle(X1,Y1,smallRadius,mPaint); //绘制两个小圆
c.drawCircle(X2,Y2,smallRadius,mPaint);
返回位图;
}
}
我们简单解释一下,利用源图像层覆盖目标图层,其次调用 PorterDuff.Mode.SRC_OUT(只在源图像和目标图像不相交的地方绘制源图像)模式来达到绘制的效果。不理解的部分,代码已经注释说明。
针对上面的混合模式不是很清楚的童鞋,可以阅读这一篇:HTTP://blog.csdn.net/aigestudio/article/details/41316141。