利用Canvas saveLayer手动绘制圆角View
来源:互联网 发布:久其数据 编辑:程序博客网 时间:2024/05/16 23:58
项目中包含了一个腾讯地图,由于腾讯地图mapView不支持圆角背景,so决定自己画四个圆角view——CornerView,覆盖在mapView上以实现圆角矩形的效果。要实现这样的效果,需要重新定义View的onDraw()方法,一般地,重写onDraw()方法需要一个Canvas对象来进行绘图(提供多种绘图API),一个Paint对象来定义颜色和绘制属性,一个Bitmap来存储绘制的图片。我把它们总结为:Canvas定义“画什么”,Paint定义了“怎么画”,Canvas包含的Bitmap定义着“画在哪”。下面我们就来对它们分别进行介绍:
Canvas:
来看下官方文档对Canvas的定义:
Class Overview
The Canvas class holds the “draw” calls. To draw something, you need 4 basic components: A Bitmap to hold the pixels, a Canvas to host the draw calls (writing into the bitmap), a drawing primitive (e.g. Rect, Path, text, Bitmap), and a paint (to describe the colors and styles for the drawing).
Canvas的主要功能为进行绘图操作,定义了“画什么”。我们可以把Canvas理解成系统提供给我们的一块内存区域(但实际上它只是一套画图的API,真正的内存是下面的Bitmap),并提供了一整套对这个内存区域进行操作的方法。Canvas类的常用方法如下:
drawRect(RectF rect, Paint paint) //绘制矩形 drawPath(Path path, Paint paint) //绘制一个路径//直接绘制bitmapdrawBitmap(Bitmap bitmap, Rect src, Rect dst, Paint paint) drawLine(float startX, float startY, float stopX, float stopY, Paintpaint) //画线drawPoint(float x, float y, Paint paint) //画点drawText(String text, float x, floaty, Paint paint) //渲染文本,Canvas类除了上面的还可以描绘文字drawOval(RectF oval, Paint paint)//画椭圆drawCircle(float cx, float cy, float radius,Paint paint)// 绘制圆drawArc(RectF oval, float startAngle, float sweepAngle, boolean useCenter, Paint paint)//画弧
canvas还有着layer(层级)的概念,Canvas提供了图层(Layer)支持,缺省情况只有一个图层Layer。可以使用SaveLayerXXX, Restore等方法创建层级,对于这些Layer是按照“栈结构“来管理的:
创建一个新的Layer到“栈”中,可以使用saveLayer, savaLayerAlpha。 从“栈”中推出一个Layer,可以使用restore,restoreToCount。当Layer入栈时,后续的DrawXXX操作都发生在这个Layer上,而Layer退栈时,就会把本层绘制的图像“绘制”到上层或是Canvas中。
Paint:
官方文档的定义:
Class Overview
The Paint class holds the style and color information about how to draw geometries, text and bitmaps.
paint类则与Canvas类关联合使用,控制着Canvas上的画笔、style等信息。定义了“怎么画”。Paint类常用方法:
setARGB(int a, int r, int g, int b) // 设置ARGB颜色值setAlpha(int a) // 设置alpha不透明度,范围为0~255setAntiAlias(boolean aa) // 是否抗锯齿setColor(int color) // 设置颜色,这里Android内部定义的有Color类包含了一些常见颜色定义setTextScaleX(float scaleX) // 设置文本缩放倍数,1.0f为原始setTextSize(float textSize) // 设置字体大小setUnderlineText(booleanunderlineText) // 设置下划线
简单地了解下Canvas和Paint,下面我们来看下自定义圆角View:CornerView的具体实现:
public class CornerView extends View { public static final int TYPE_LEFT_TOP = 1; public static final int TYPE_RIGHT_TOP = 2; public static final int TYPE_RIGHT_BOTTOM = 3; public static final int TYPE_LEFT_BOTTOM = 4; private int mType = TYPE_LEFT_TOP; private float mWidth; private float mHeight; private Paint mPaint; public CornerView(Context context) { this(context, null); } public CornerView(Context context, AttributeSet attrs) { this(context, attrs, 0); } public CornerView(Context context, AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); mPaint = new Paint(Paint.ANTI_ALIAS_FLAG); } public void setType(int type) { mType = type; } @Override protected void onLayout(boolean changed, int left, int top, int right, int bottom) { super.onLayout(changed, left, top, right, bottom); mWidth = getMeasuredWidth(); mHeight = getMeasuredHeight(); } @Override protected void onDraw(Canvas canvas) { super.onDraw(canvas); drawCorner(canvas); } private void drawCorner(Canvas canvas) { //新建Canvas层级 int saveCount = canvas.saveLayer(0, 0, getWidth(), getHeight(), null, Canvas.ALL_SAVE_FLAG); //画背景色,这里为紫色 canvas.drawColor(getResources().getColor(R.color.purple)); //设置dst_out ,意味着接下来画的view不会显示,只是做差集 mPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.DST_OUT)); //四种方向的圆角 switch (mType) { case TYPE_LEFT_TOP: canvas.drawCircle(mWidth, mHeight, mWidth, mPaint); break; case TYPE_RIGHT_TOP: canvas.drawCircle(0, mHeight, mWidth, mPaint); break; case TYPE_RIGHT_BOTTOM: canvas.drawCircle(0, 0, mWidth, mPaint); break; case TYPE_LEFT_BOTTOM: canvas.drawCircle(mWidth, 0, mWidth, mPaint); break; } //将如上画的层覆盖到原有层级上 canvas.restoreToCount(saveCount); }}
代码关键部分在drawCorner()方法,这里定义了canvas的layer(层级):通过saveLayer方法新建一层级,再通过restoreToCount方法将新层还原回画布,这样就不会对原有的层进行干扰。
此外这里还采用了PorterDuffXfermode,DST_OUT代表原有的背景和新draw的View的差集。其它的PorterDuffXfermode如下所示:
另外还需注意一点,不要在View的onMeasure,onLayout,onDraw方法内部做任何的构建对象的操作,因为它们可能执行多次,影响程序的性能。 类似于mPaint = new Paint(Paint.ANTI_ALIAS_FLAG); 这种代码要放在初始化中执行。
最后在外部RelativeLayout中add进四个CornerView。其中一段代码如下:
CornerView view0 = new SGCornerView(context);view0.setType(CornerView.TYPE_LEFT_TOP);this.addView(view0);lp = (LayoutParams) view0.getLayoutParams();lp.width = DensityUtil.dip2px(context, 10f);lp.height = DensityUtil.dip2px(context, 10f);lp.addRule(RelativeLayout.ALIGN_PARENT_LEFT);lp.addRule(RelativeLayout.ALIGN_PARENT_TOP);view0.setLayoutParams(lp);
效果如下,我截的不好,其实没有紫色的边的
- 利用Canvas saveLayer手动绘制圆角View
- Android view利用canvas绘制动画(一)
- View.onDraw(Canvas canvas)绘制
- HTML5 JS Canvas利用贝塞尔曲线绘制圆角矩形
- Canvas的saveLayer理解
- canvas的saveLayer理解
- 利用canvas绘制钟表
- Canvas绘制圆角矩形
- 利用Canvas绘制雷达图
- Android中图形的绘制-----自定义View(利用canvas和Path相结合)
- Canvas利用圆绘制正余弦函数叠加图像
- 自定义View,在Canvas上绘制几何图形
- Android自定义View---Canvas绘制贝塞尔曲线
- 自定义View之canvas绘制时钟
- 自定义View进阶-Canvas之绘制图形
- 自定义View进阶-Canvas之绘制图形
- 自定义View起步:Canvas之绘制图片
- 自定义View起步:Canvas之绘制文字
- 【贪心】bzoj 3709:[PA2014]Bohater
- xml布局中实现文字下划线的效果
- Unity 5.2.1 UGUI 控件使用
- 策略模式与简单工厂结合
- android自定义ListView高度设置无效
- 利用Canvas saveLayer手动绘制圆角View
- TopCoder SRM 677 Div. 2 550 - FourStrings (枚举)
- 开荒新系列之LeetCode: 006-Valid Anagram
- 图片的裁剪与压缩
- Mac OSX 中java7 java8环境的配置
- Linux编程之一:创建第一个C/C++程序
- 精准测试之项目案例实战大剖析
- 【LCA】bzoj 2144:跳跳棋
- 【codevs1250】Fibonacci数列,矩阵乘法入门