重写ImageView使用Xfermode遮罩实现圆角和圆形

来源:互联网 发布:更改数据库名称 编辑:程序博客网 时间:2024/05/22 08:11

重写ImageView,并且在画布上绘制出四个角,使用DST_OUT取图模式对图片取出;



网上各种案例都有给出上面的实现方法,那么就来说说怎么实现



首先绘制出4个角,然后叠加而成,叠加的时候使用DST_OUT取图模式把图片取出即可;

看一下布局:

<?xml version="1.0" encoding="utf-8"?><LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"    android:layout_width="match_parent"    android:layout_height="match_parent"    android:orientation="vertical" >    <zy.zh.view.View1        android:layout_width="170dp"        android:layout_height="100dp"        android:layout_margin="10dp" />        <ImageView         android:layout_width="wrap_content"        android:layout_height="wrap_content"        android:src="@drawable/ic_android"        android:contentDescription="@null"        android:layout_marginLeft="10dp"        />    <zy.zh.view.View2        android:id="@+id/view"        android:layout_width="wrap_content"        android:layout_height="wrap_content"android:src="@drawable/ic_android"android:contentDescription="@null"        android:layout_margin="10dp" />    </LinearLayout>

先是zy.zh.view.View1控件绘出了4个角,然后合并即可;

关于zy.zh.view.View1的实现:

package zy.zh.view;import android.content.Context;import android.graphics.Canvas;import android.graphics.Color;import android.graphics.Paint;import android.graphics.Path;import android.graphics.RectF;import android.util.AttributeSet;import android.view.View;public class View1 extends View {private int cornerSize = 30;private Paint paint;public View1(Context context, AttributeSet attrs) {super(context, attrs);paint = new Paint();paint.setColor(Color.BLUE);paint.setAntiAlias(true);//消除锯齿}@Overridepublic void draw(Canvas canvas) {super.draw(canvas);drawLeftTop(canvas);drawRightTop(canvas);drawLeftBottom(canvas);drawRightBottom(canvas);}private void drawLeftTop(Canvas canvas) {Path path = new Path();path.moveTo(0, cornerSize);path.lineTo(0, 0);path.lineTo(cornerSize, 0);path.arcTo(new RectF(0, 0, cornerSize * 2, cornerSize * 2), -90, -90);path.close();canvas.drawPath(path, paint);}private void drawLeftBottom(Canvas canvas) {Path path = new Path();path.moveTo(0, getHeight() - cornerSize);path.lineTo(0, getHeight());path.lineTo(cornerSize, getHeight());path.arcTo(new RectF(0, // xgetHeight() - cornerSize * 2,// ycornerSize * 2,// xgetHeight()// getWidth()// y), 90, 90);path.close();canvas.drawPath(path, paint);}private void drawRightBottom(Canvas canvas) {Path path = new Path();path.moveTo(getWidth() - cornerSize, getHeight());path.lineTo(getWidth(), getHeight());path.lineTo(getWidth(), getHeight() - cornerSize);RectF oval = new RectF(getWidth() - cornerSize * 2, getHeight()- cornerSize * 2, getWidth(), getHeight());path.arcTo(oval, 0, 90);path.close();canvas.drawPath(path, paint);}private void drawRightTop(Canvas canvas) {Path path = new Path();path.moveTo(getWidth(), cornerSize);path.lineTo(getWidth(), 0);path.lineTo(getWidth() - cornerSize, 0);path.arcTo(new RectF(getWidth() - cornerSize * 2, 0, getWidth(),0 + cornerSize * 2), -90, 90);path.close();canvas.drawPath(path, paint);}}

其中的4个函数方别绘制4个角。

Path函数在绘制的时候默认是实心的所有绘制了封闭图形后自动填充实心,何况还有path.close()方法的调用,使用的arcTo,这个接口的说明是:If the start of the path is different from the path's current last point, then an automatic lineTo() is added to connect the current contour to the start of the arc. 

那么就是说path最好是按顺序作画,否则缺口会自动接上;所以绘制的路径方向要一致,关于方向一致的问题,绘图过程中自己会明白。

下面看一下怎么使用DST_OUT取图模式把图取出来:

package zy.zh.view;import android.content.Context;import android.graphics.Bitmap;import android.graphics.Bitmap.Config;import android.graphics.Canvas;import android.graphics.Color;import android.graphics.Paint;import android.graphics.Path;import android.graphics.PorterDuff;import android.graphics.PorterDuffXfermode;import android.graphics.RectF;import android.util.AttributeSet;import android.widget.ImageView;public class View2 extends ImageView {private int cornerSize = 30;private Paint paint;public View2(Context context, AttributeSet attrs) {super(context, attrs);paint = new Paint();paint.setColor(Color.BLUE);paint.setAntiAlias(true);PorterDuff.Mode mode;mode = PorterDuff.Mode.SRC_OUT;// 正确截图 paint.setXfermode(new PorterDuffXfermode(mode));// 设置取图模式}@Overridepublic void draw(Canvas canvas) {Bitmap bitmap = Bitmap.createBitmap(getWidth(), getHeight(),Config.ARGB_8888);Canvas canvas2 = new Canvas(bitmap);super.draw(canvas2);drawLeftTop(canvas2);// 这样canvas2就带有了取图模式,那就是SrcdrawRightTop(canvas2);drawLeftBottom(canvas2);drawRightBottom(canvas2);canvas.drawBitmap(bitmap, 0, 0, null);// canvas作为Dst;bitmap.recycle();}private void drawLeftTop(Canvas canvas) {Path path = new Path();path.moveTo(0, cornerSize);path.lineTo(0, 0);path.lineTo(cornerSize, 0);path.arcTo(new RectF(0, 0, cornerSize * 2, cornerSize * 2), -90, -90);path.close();canvas.drawPath(path, paint);}private void drawLeftBottom(Canvas canvas) {Path path = new Path();path.moveTo(0, getHeight() - cornerSize);path.lineTo(0, getHeight());path.lineTo(cornerSize, getHeight());path.arcTo(new RectF(0, // xgetHeight() - cornerSize * 2,// ycornerSize * 2,// xgetHeight()// getWidth()// y), 90, 90);path.close();canvas.drawPath(path, paint);}private void drawRightBottom(Canvas canvas) {Path path = new Path();path.moveTo(getWidth() - cornerSize, getHeight());path.lineTo(getWidth(), getHeight());path.lineTo(getWidth(), getHeight() - cornerSize);RectF oval = new RectF(getWidth() - cornerSize * 2, getHeight()- cornerSize * 2, getWidth(), getHeight());path.arcTo(oval, 0, 90);path.close();canvas.drawPath(path, paint);}private void drawRightTop(Canvas canvas) {Path path = new Path();path.moveTo(getWidth(), cornerSize);path.lineTo(getWidth(), 0);path.lineTo(getWidth() - cornerSize, 0);path.arcTo(new RectF(getWidth() - cornerSize * 2, 0, getWidth(),0 + cornerSize * 2), -90, 90);path.close();canvas.drawPath(path, paint);}}

这里值得注意的是如果Paint在draw方法中进行实例化会黄色警告Avoid object allocations during draw/layout operations,就是提醒:避免在draw和layout中进行对象分配;


还有另外一种方法绘制圆角ImageView,那么就是使用安卓sdk给出的drawRoundRect绘制圆角矩形;


布局为:

<?xml version="1.0" encoding="utf-8"?><LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"    android:layout_width="match_parent"    android:layout_height="match_parent"    android:orientation="vertical" >    <zy.zh.view.View3        android:layout_width="170dp"        android:layout_height="100dp"        android:layout_margin="10dp" />        <ImageView         android:layout_width="wrap_content"        android:layout_height="wrap_content"        android:src="@drawable/ic_android"        android:contentDescription="@null"        android:layout_marginLeft="10dp"        />    <zy.zh.view.View4        android:id="@+id/view"        android:layout_width="wrap_content"        android:layout_height="wrap_content"android:src="@drawable/ic_android"android:contentDescription="@null"        android:layout_margin="10dp" />    </LinearLayout>
其中的View3:

package zy.zh.view;import android.content.Context;import android.graphics.Canvas;import android.graphics.Color;import android.graphics.Paint;import android.graphics.Rect;import android.graphics.RectF;import android.util.AttributeSet;import android.view.View;public class View3 extends View{public View3(Context context, AttributeSet attrs) {super(context, attrs);}@Overridepublic void draw(Canvas canvas) {super.draw(canvas);final Paint paint = new Paint();final RectF rectF = new RectF(new Rect(0, 0, getWidth(),getHeight()));final float roundPx = 30;paint.setAntiAlias(true);canvas.drawARGB(0, 0, 0, 0);paint.setColor(Color.RED);canvas.drawRoundRect(rectF, roundPx, roundPx, paint);}}


View4:

package zy.zh.view;import android.content.Context;import android.graphics.Bitmap;import android.graphics.Bitmap.Config;import android.graphics.Canvas;import android.graphics.Color;import android.graphics.Paint;import android.graphics.PorterDuff.Mode;import android.graphics.PorterDuffXfermode;import android.graphics.Rect;import android.graphics.RectF;import android.util.AttributeSet;import android.widget.ImageView;public class View4 extends ImageView {public View4(Context context, AttributeSet attrs) {super(context, attrs);}@Overridepublic void draw(Canvas canvas) {Bitmap bitmap;bitmap = Bitmap.createBitmap(getWidth(), getHeight(), Config.ARGB_8888);Canvas canvas2 = new Canvas(bitmap);super.draw(canvas2);bitmap = GetRoundedCornerBitmap(bitmap);canvas.drawBitmap(bitmap, 0, 0, null);}public static Bitmap GetRoundedCornerBitmap(Bitmap bitmap) {try {Bitmap output = Bitmap.createBitmap(bitmap.getWidth(),bitmap.getHeight(), Config.ARGB_8888);Canvas canvas = new Canvas(output);final Paint paint = new Paint();final RectF rectF = new RectF(new Rect(0, 0, bitmap.getWidth(),bitmap.getHeight()));final float roundPx = 30;paint.setAntiAlias(true);canvas.drawARGB(0, 0, 0, 0);paint.setColor(Color.BLACK);canvas.drawRoundRect(rectF, roundPx, roundPx, paint);paint.setXfermode(new PorterDuffXfermode(Mode.SRC_IN));final Rect src = new Rect(0, 0, bitmap.getWidth(),bitmap.getHeight());final Rect rect = new Rect(0, 0, bitmap.getWidth(),bitmap.getHeight());canvas.drawBitmap(bitmap, src, rect, paint);return output;} catch (Exception e) {return bitmap;}}}


同理我们也可以这个方法绘制圆形之后进行取图,就能取到圆形ImageView了。


这里增加了描边;

package zy.zh.view;import android.content.Context;import android.graphics.Bitmap;import android.graphics.Bitmap.Config;import android.graphics.Canvas;import android.graphics.Color;import android.graphics.Paint;import android.graphics.PorterDuff.Mode;import android.graphics.PorterDuffXfermode;import android.graphics.Rect;import android.util.AttributeSet;import android.widget.ImageView;public class View5 extends ImageView {public View5(Context context, AttributeSet attrs) {super(context, attrs);}@Overridepublic void draw(Canvas canvas) {Bitmap bitmap;bitmap = Bitmap.createBitmap(getWidth(), getHeight(), Config.ARGB_8888);Canvas canvas2 = new Canvas(bitmap);super.draw(canvas2);bitmap = GetRoundedCornerBitmap(bitmap);canvas.drawBitmap(bitmap, 0, 0, null);// bitmap.recycle();addStroke(canvas);// 增加描边}// 画一个正圆形private Bitmap GetRoundedCornerBitmap(Bitmap bitmap) {Bitmap result = Bitmap.createBitmap(bitmap.getWidth(),bitmap.getHeight(), Config.ARGB_8888);Canvas canvas = new Canvas(result);Paint paint = new Paint();paint.setAntiAlias(true);// // 消除锯齿canvas.drawARGB(0, 0, 0, 0);paint.setStrokeWidth(5);// 外宽高度canvas.drawCircle(bitmap.getWidth() / 2, bitmap.getHeight() / 2,bitmap.getHeight() / 2, paint);paint.setXfermode(new PorterDuffXfermode(Mode.SRC_IN));final Rect src = new Rect(0, 0, bitmap.getWidth(), bitmap.getHeight());final Rect rect = new Rect(0, 0, bitmap.getWidth(), bitmap.getHeight());canvas.drawBitmap(bitmap, src, rect, paint);return result;}/**增加描边*/private void addStroke(Canvas canvas) {Paint paint = new Paint();paint.setAntiAlias(true);// // 消除锯齿canvas.drawARGB(0, 0, 0, 0);paint.setStrokeWidth(5);// 外宽高度paint.setColor(Color.RED);// 当然也可以设置为"实心"(Paint.Style.FILL)paint.setStyle(Paint.Style.STROKE);canvas.drawCircle(getWidth() / 2, getHeight() / 2,(float) (getHeight() / 2 - 2.5), paint);}}


暂时总结上面两种使用遮罩的方法;

转载请注明:http://blog.csdn.net/dreamintheworld/article/details/44116049


0 0
原创粉丝点击