自定义圆角ImageView

在Android开发的过程中,我们常常需要显示不同形状的图片(圆角、或圆形等),而网上的很多例子都是直接使用集成View然后重写onDraw的方法去实现,这样的方式固然简单直接,但这样做的话会失去很多重要实用的ImageView特性(例如:scaletype)。因此,本文旨在举出下面例子,展示自定义圆角ImageView的基本方法和原理。


XMl布局代码:

<span style="font-family:Microsoft YaHei;font-size:14px;"><?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:background="#000000"
    android:orientation="vertical" >
    

<ImageView
    android:id="@+id/imageView"
    android:layout_width="200dp"
    android:layout_height="200dp"
    android:layout_gravity="center"
    android:src="@drawable/bg_00"/>

<com.example.component.ShapeImageView
    android:id="@+id/shapeImageView"
    android:layout_width="200dp"
    android:layout_height="200dp"
    android:layout_gravity="center"
    android:src="@drawable/bg_00"/>


</LinearLayout>
</span>


Java代码:

<span style="font-family:Microsoft YaHei;font-size:14px;">public class ShapeImageView extends ImageView {
	public static final String TAG = "ShapeImageView";

	public static final int RECTANGLE= 0;
	public static final int ROUND_RECTANGLE = 1;
	public static final int CIRCLE = 2;

	/**圆角矩形的四角弧度,单位是像素*/
	private static final int RADIUS_X = 20;
	private static final int RADIUS_Y = 20;

	private Bitmap mShapeBmp=null;
	private BitmapDrawable mBmpDrawable = null;
	private int mShape = ROUND_RECTANGLE;
	private int mRadiusX = RADIUS_X;
	private int mRadiusY = RADIUS_Y;

	private int mWidth;
	private int mHeight;


	//paint的遮罩层,canvas在绘制原图和下一张图时,两者的交互绘制模式(相交、合并、异或等)
	private PorterDuffXfermode xfermode=new PorterDuffXfermode(PorterDuff.Mode.SRC_IN);
	//Paint的标识绘制过滤器,用于设置图片绘制的抗锯齿效果
	private PaintFlagsDrawFilter pdf=new PaintFlagsDrawFilter(0, Paint.ANTI_ALIAS_FLAG|Paint.FILTER_BITMAP_FLAG);


	public ShapeImageView(Context context, AttributeSet attrs, int defStyle) {
		super(context, attrs, defStyle);
	}

	public ShapeImageView(Context context, AttributeSet attrs) {
		super(context, attrs);
	}

	public ShapeImageView(Context context) {
		super(context);
	}

	public int getShape() {
		return mShape;
	}

	public void setShape(int mShape) {
		this.mShape = mShape;
	}

	public int getRadiusX() {
		if(mShape == ROUND_RECTANGLE)
			return mRadiusX;
		else
			return 0;
	}

	public int getRadiusY() {
		if(mShape == ROUND_RECTANGLE)
			return mRadiusY;
		else
			return 0;
	}


	/**
	 * 设置圆角矩形的弧度(当shape=ROUND_TANGLE才有效)
	 * @param mRadiusX
	 */
	public void setRadius(int radiusX, int radiusY) {
		if(mShape == ROUND_RECTANGLE){
			this.mRadiusX = radiusX;
			this.mRadiusY = radiusY;
		}
	}

	/**
	 * 生成几何蒙版bitmap,即创建图片想要的几何形状(圆角、圆形等)的底板,用于与原图相交绘制
	 * @param w
	 * @param h
	 * @return
	 */
	private Bitmap getShapeBitmap(int width, int height, Bitmap bitmapSrc, int shape) 
	{
		float widthScaleRatio, heightScaleRatio;//缩放比例,用于缩放圆角,使显示的圆角总是XY半径相等
		int bmpSrcWidth = bitmapSrc.getWidth();
		int bmpSrcHeight = bitmapSrc.getHeight();
		Bitmap bmpDst = Bitmap.createBitmap(bmpSrcWidth, bmpSrcHeight, Config.ARGB_8888);//创建蒙板bitmap
		Canvas canvas = new Canvas(bmpDst);//创建蒙板画布
		Paint p = new Paint(Paint.ANTI_ALIAS_FLAG);//创建透明抗锯齿画笔
		p.setColor(Color.parseColor("#ffffffff")); 

		widthScaleRatio = (1.0f*bmpSrcWidth)/(1.0f*width);//原图与目标bounds的缩放比例
		heightScaleRatio = (1.0f*bmpSrcHeight)/(1.0f*height);
		canvas.setDrawFilter(pdf);
		
		//根据shape值绘制不同的几何蒙版
		switch (shape) {
		case ROUND_RECTANGLE:
			canvas.drawRoundRect(new RectF(0,0,bmpSrcWidth,bmpSrcHeight), 
					mRadiusX*widthScaleRatio, mRadiusY*heightScaleRatio, p);//绘制蒙版bitmap(PS:圆角的半径的单位是像素)
			break;
		case CIRCLE:
			canvas.drawOval(new RectF(0,0,bmpSrcWidth,bmpSrcHeight), p);//绘制蒙版bitmap(PS:圆角的半径的单位是像素)
			break;
		default:
			break;
		}
		
		p.setXfermode(xfermode);
		canvas.drawBitmap(bitmapSrc, null, new RectF(0,0,bmpSrcWidth, bmpSrcHeight), p);//绘制原图并相交得出最终圆角图片
		p.setXfermode(null);

		return bmpDst;
	}
	


	@Override
	protected void onDraw(Canvas canvas) {

		if(getDrawable() instanceof BitmapDrawable && getDrawable()!=null){
			mBmpDrawable = (BitmapDrawable) getDrawable();
			if(!mBmpDrawable.getBitmap().equals(mShapeBmp)){
				mWidth = getWidth();
				mHeight = getHeight();
				mShapeBmp = getShapeBitmap(mWidth,mHeight, mBmpDrawable.getBitmap(), mShape);
				BitmapDrawable drawable = new BitmapDrawable(mShapeBmp);
				setImageDrawable(drawable);
				return;
			}

		}

		super.onDraw(canvas);
	}


}</span>


实现原理:

1.绘制与原图同样大小的几何蒙板

2.在该蒙板上绘制原图,并利用paint对象的PorterDuffXfermode图层交互特性,仅绘制出原图与蒙版相交的区域



相比继承View的方法,这种方法比较大的好处在于,当我们需要静态设置图片的时候,只需要在XML布局文件中相应的src属性上添加,而免去了要在java代码中手动设置的麻烦,减少了代码的耦合度,同时还能享受原来ImageView的各种特性。


由于模拟器最近出了点问题,图片就不贴了,大家使用这种方法试试看,相互学习交流。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值