自定义ImageView圆图实现

首先很感谢开源项目Universal Image Loader图片加载框架。之前也看过一段时间框架源码,但是却没有时间进行知识点的总结。

今天项目遇到了需要实现圆头像的编辑显示,Universal就已经提供了这个显示RoundedBitmapDisplayer这个类实现了圆图功能。看它的代码可以发现是实现的Drawable

public static class RoundedDrawable extends Drawable {

		protected final float cornerRadius;
		protected final int margin;

		protected final RectF mRect = new RectF(),
				mBitmapRect;
		protected final BitmapShader bitmapShader;
		protected final Paint paint;

		public RoundedDrawable(Bitmap bitmap, int cornerRadius, int margin) {
			this.cornerRadius = cornerRadius;
			this.margin = margin;

			bitmapShader = new BitmapShader(bitmap, Shader.TileMode.CLAMP, Shader.TileMode.CLAMP);
			mBitmapRect = new RectF (margin, margin, bitmap.getWidth() - margin, bitmap.getHeight() - margin);
			
			paint = new Paint();
			paint.setAntiAlias(true);
			paint.setShader(bitmapShader);
		}

		@Override
		protected void onBoundsChange(Rect bounds) {
			super.onBoundsChange(bounds);
			mRect.set(margin, margin, bounds.width() - margin, bounds.height() - margin);
			
			// Resize the original bitmap to fit the new bound
			Matrix shaderMatrix = new Matrix();
			shaderMatrix.setRectToRect(mBitmapRect, mRect, Matrix.ScaleToFit.FILL);
			bitmapShader.setLocalMatrix(shaderMatrix);
			
		}

		@Override
		public void draw(Canvas canvas) {
			canvas.drawRoundRect(mRect, cornerRadius, cornerRadius, paint);
		}

		@Override
		public int getOpacity() {
			return PixelFormat.TRANSLUCENT;
		}

		@Override
		public void setAlpha(int alpha) {
			paint.setAlpha(alpha);
		}

		@Override
		public void setColorFilter(ColorFilter cf) {
			paint.setColorFilter(cf);
		}
	}

其实总结下来,上面圆图实现步骤就是 1、通过bitmap初始化位图着色器BitmapShader类,2、计算bitmap原始图片的rect,3、计算放置图片需要的rect。4、使用Matrix类对两个rect进行压缩,然后复制给BitmapShader着色器里去。最后是画布画图。(刚开始一直以为shader是阴影的意思,原来有道一下是着色器的意思,这个翻译其实对我理解代码还是很重要的,所以不要想当然,要勤奋点,这个是优秀程序员必备要素。)


最后我要实现的是继承ImageView实现圆图

public class URoundedImageView extends ImageView {

	private Paint mBitmapPaint,mBackgroundPaint;
	
	private BitmapShader mBitmapShader;
	
	private RectF mBitmapRect , mRect;
	
	private int borderWidth;
	
	private Bitmap mBitmap;
	
	private Matrix shaderMatrix;
	
	public URoundedImageView(Context context, AttributeSet attrs,
			int defStyleAttr) {
		super(context, attrs, defStyleAttr);
		init();
	}

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

	public URoundedImageView(Context context) {
		super(context);
		init();
	}
	
	private void init(){
		mBitmapPaint = new Paint();
		mBitmapPaint.setAntiAlias(true);
		
		mBackgroundPaint = new Paint();
		mBackgroundPaint.setAntiAlias(true);
		mBackgroundPaint.setColor(Color.WHITE);
		
		borderWidth = 5;
		
		mRect = new RectF();
		shaderMatrix = new Matrix();
	}
	
	@Override
	protected void onLayout(boolean changed, int left, int top, int right,
			int bottom) {
		// TODO Auto-generated method stub
		super.onLayout(changed, left, top, right, bottom);
	}
	
	@Override
	protected void onDraw(Canvas canvas) {
		mBitmap = ((BitmapDrawable) getDrawable()).getBitmap();
		
		if (getWidth() == 0 || getHeight() == 0 || mBitmap == null) {
			return;
		}
		int w = getWidth();
		int h = getHeight();
		int radius = Math.min(w, h) / 2;
		
		canvas.drawCircle(w / 2, h / 2, radius, mBackgroundPaint);
		
		//传入bitmap初始化位图着色器
		if (mBitmapShader == null) {
			mBitmapShader = new BitmapShader(mBitmap, Shader.TileMode.CLAMP,
					Shader.TileMode.CLAMP);
		}
		if (mBitmapRect == null) {
			mBitmapRect = new RectF(borderWidth, borderWidth,
					mBitmap.getWidth() - borderWidth, mBitmap.getHeight()
							- borderWidth);
		}
		mBitmapPaint.setShader(mBitmapShader);
		
		mRect.set(borderWidth, borderWidth, w - borderWidth, h - borderWidth);
		
		//对bitmap原始图进行缩放
		shaderMatrix.setRectToRect(mBitmapRect, mRect, Matrix.ScaleToFit.FILL);
		mBitmapShader.setLocalMatrix(shaderMatrix);
		
		canvas.drawRoundRect(mRect, radius, radius, mBitmapPaint);
	}

}

刚开始写的不够规范,直接在ondraw方法里面new一些需要的对象,lint提醒我们Avoid object allocations during draw/layout operations (preallocate and reuse instead)这个warning。因为ondraw会不断调用,如果一直new对象的话会吃内存。所以为了避免重复new对象,根据自己的需求进行判空操作。具体根据自己需求来优化代码,有时候为了达到需求也没办法做到在ondraw方法里不出现重复new对象的现象。


总结:多参考优秀的开源项目,用正确的方法做正确的事情!







评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值