您的位置:首页 > Web前端

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

2015-03-07 14:00 513 查看
重写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);//消除锯齿
	}

	@Override
	public 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, // x
				getHeight() - cornerSize * 2,// y
				cornerSize * 2,// x
				getHeight()// 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));// 设置取图模式
	}

	@Override
	public void draw(Canvas canvas) {
		Bitmap bitmap = Bitmap.createBitmap(getWidth(), getHeight(),
				Config.ARGB_8888);
		Canvas canvas2 = new Canvas(bitmap);
		super.draw(canvas2);
		drawLeftTop(canvas2);// 这样canvas2就带有了取图模式,那就是Src
		drawRightTop(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, // x
				getHeight() - cornerSize * 2,// y
				cornerSize * 2,// x
				getHeight()// 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);
	}

	@Override
	public 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);
	}

	@Override
	public 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);
	}

	@Override
	public 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);
	}
	
}


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

转载请注明:/article/2710220.html
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: