1. 程式人生 > >Android 三種方式實現圓形ImageView

Android 三種方式實現圓形ImageView

所有方式均繼承了ImageView

圓形圖片實現一:BitmapShader

package com.open.widget;

import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapShader;
import android.graphics.Canvas;
import android.graphics.Matrix;
import android.graphics.Paint;
import android.graphics.RectF;
import android.graphics.Shader.TileMode;
import android.graphics.drawable.BitmapDrawable;
import android.graphics.drawable.Drawable;
import android.util.AttributeSet;
import android.widget.ImageView;
/**
 * 1.BitmapShader
 * 
 * @author Administrator
 *
 */
public class CircularImageView extends ImageView {

	private BitmapShader mBitmapShader;
	private Paint mBitmapPaint = new Paint();
	private RectF mRoundRect=new RectF();

	public CircularImageView(Context context) {
		super(context);
		initObjectAttribute();
	}

	public CircularImageView(Context context, AttributeSet attrs) {
		this(context, attrs, 0);
	}

	public CircularImageView(Context context, AttributeSet attrs, int defStyleAttr) {
		super(context, attrs, defStyleAttr);
		
		initObjectAttribute();		
	}

	@Override
	public void setImageResource(int resId) {
		super.setImageResource(resId);
		createBitmapShader();
	}

	@Override
	public void setImageBitmap(Bitmap bm) {
		super.setImageBitmap(bm);
//		createBitmapShader();
	}

	@Override
	public void setImageDrawable(Drawable drawable) {
		super.setImageDrawable(drawable);
		createBitmapShader();
	}

	private void initObjectAttribute()
	{
		mBitmapPaint.setAntiAlias(true);
//		if(getScaleType() != ScaleType.CENTER_CROP)
//		{
//			setScaleType(ScaleType.CENTER_CROP);
//		}
	}

	private void createBitmapShader()
	{
		mBitmapShader = null;
		Drawable mDrawable = getDrawable();
		if (mDrawable == null)
		{
			return;
		}
		
		if(mDrawable instanceof BitmapDrawable)
		{
			BitmapDrawable bd = (BitmapDrawable) mDrawable;
			Bitmap bitmap = bd.getBitmap();
			mBitmapShader = new BitmapShader(bitmap, TileMode.CLAMP, TileMode.CLAMP);
		}
		else //if Drawable instanceof NinePathDrawable ,the code below is bad , because a view reference two bitmap ( one in NinePath , other is here) 
		{
			int w = mDrawable.getIntrinsicWidth();
			int h = mDrawable.getIntrinsicHeight();
			
			Bitmap bitmap = Bitmap.createBitmap(w, h, Bitmap.Config.ARGB_8888);
			Canvas canvas = new Canvas(bitmap);
			mDrawable.setBounds(0, 0, w, h);
			mDrawable.draw(canvas);
			mBitmapShader = new BitmapShader(bitmap, TileMode.CLAMP, TileMode.CLAMP);
		}
	}
	
	@Override
	protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
		super.onMeasure(widthMeasureSpec, heightMeasureSpec);
		mRoundRect.set(0,0,getMeasuredWidth(),getMeasuredHeight());
	}

	@Override
	protected void onDraw(Canvas canvas) {
		
		Drawable mDrawable = getDrawable();
		if (null == mDrawable || null == mBitmapShader)
		{
			return;
		}
		Matrix  mDrawMatrix= getImageMatrix();
		if(null == mDrawMatrix)
		{
			mDrawMatrix =new Matrix();
		}
		mBitmapShader.setLocalMatrix(mDrawMatrix);
		mBitmapPaint.setShader(mBitmapShader);
		canvas.drawCircle(getWidth()/2, getHeight()/2, Math.min(getWidth()/2, getHeight()/2), mBitmapPaint);
	}
}


圓形圖片實現二:Path

package com.open.widget;

import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Matrix;
import android.graphics.Paint;
import android.graphics.PaintFlagsDrawFilter;
import android.graphics.Path;
import android.graphics.RectF;
import android.graphics.Region;
import android.graphics.drawable.Drawable;
import android.util.AttributeSet;
import android.widget.ImageView;
/**
 * 2.Path
 * 
 * @author Administrator
 *
 */
public class CircularImageView2 extends ImageView {

	private RectF mRoundRect=new RectF();
	private Path mPath = new Path();
	private PaintFlagsDrawFilter pfd=new PaintFlagsDrawFilter(0, Paint.ANTI_ALIAS_FLAG|Paint.FILTER_BITMAP_FLAG);
	
	public CircularImageView2(Context context) {
		super(context);
		initObjectAttribute();
	}

	public CircularImageView2(Context context, AttributeSet attrs) {
		this(context, attrs, 0);
	}

	public CircularImageView2(Context context, AttributeSet attrs, int defStyleAttr) {
		super(context, attrs, defStyleAttr);
		
		initObjectAttribute();		
	}

	private void initObjectAttribute()
	{
//		if(getScaleType() != ScaleType.CENTER_CROP)
//		{
//			setScaleType(ScaleType.CENTER_CROP);
//		}
	}
	
	@Override
	protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
		super.onMeasure(widthMeasureSpec, heightMeasureSpec);
		mRoundRect.set(0,0,getMeasuredWidth(),getMeasuredHeight());
	}

	@Override
	protected void onDraw(Canvas canvas) {
		Drawable mDrawable = getDrawable();
		if (mDrawable == null)
		{
			return;
		}
        
        if (mDrawable.getIntrinsicWidth() == 0 || mDrawable.getIntrinsicHeight() == 0) {
            return;     // nothing to draw (empty bounds)
        }
        canvas.setDrawFilter(pfd); 
        canvas.save();
        
        mPath.reset();
        canvas.clipPath(mPath); // makes the clip empty

        mPath.addCircle(getWidth()/2, getHeight()/2, Math.min(getWidth()/2, getHeight()/2), Path.Direction.CCW);
        canvas.clipPath(mPath, Region.Op.REPLACE);

        
        Matrix mDrawMatrix = getImageMatrix();
        if (mDrawMatrix != null) {
            canvas.concat(mDrawMatrix);
        }
        mDrawable.draw(canvas);
        
        canvas.restore();
	}
}


圓形圖片實現三:setXfermode

package com.open.widget;

import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.PorterDuff;
import android.graphics.PorterDuffXfermode;
import android.graphics.RectF;
import android.graphics.Xfermode;
import android.graphics.drawable.Drawable;
import android.util.AttributeSet;
import android.widget.ImageView;

/**
 * 3.setXfermode
 * 
 * @author Administrator
 *
 */
public class CircularImageView3 extends ImageView {
	
	private Paint paint = new Paint();  
	private Xfermode mXfermode = new PorterDuffXfermode(PorterDuff.Mode.DST_IN);
	private Bitmap maskBitmap=null;
	private RectF mRoundRect=new RectF();
	private int oldWidth;
	private int oldHeight;
	
	public CircularImageView3(Context context) {
		super(context);
		initObjectAttribute();
	}

	public CircularImageView3(Context context, AttributeSet attrs) {
		this(context, attrs, 0);
	}

	public CircularImageView3(Context context, AttributeSet attrs, int defStyleAttr) {
		super(context, attrs, defStyleAttr);
		
		initObjectAttribute();		

	}

	private void initObjectAttribute()
	{
        paint.setFlags(Paint.ANTI_ALIAS_FLAG);  
        paint.setAntiAlias(true);// 設定畫筆的鋸齒效果。 true是去除,大家一看效果就明白了   
        
//		if(getScaleType() != ScaleType.CENTER_CROP)
//		{
//			setScaleType(ScaleType.CENTER_CROP);
//		}
	}
	
	private void create_mask_bitmap(int w , int h)
	{
		if(null != maskBitmap && !maskBitmap.isRecycled())
		{
			maskBitmap.recycle();
			maskBitmap=null;
		}
		
		maskBitmap = Bitmap.createBitmap(w, h, Bitmap.Config.ARGB_8888);  
        Canvas mCanvas = new Canvas(maskBitmap);  
        Paint mPaint = new Paint(Paint.ANTI_ALIAS_FLAG);    
        mPaint.setColor(Color.TRANSPARENT);  
        mCanvas.drawCircle(w/2, h/2, Math.min(w/2, h/2), paint);
	}
	
	@Override
	protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
		super.onMeasure(widthMeasureSpec, heightMeasureSpec);
		mRoundRect.set(0,0,getMeasuredWidth(),getMeasuredHeight());
		
		if( oldWidth!=getMeasuredWidth() || oldHeight!=getMeasuredHeight() )
		{
			oldWidth = getMeasuredWidth() ;
			oldHeight = getMeasuredHeight();
			
			if(oldWidth > 0 && oldHeight >0)
			{
				create_mask_bitmap(oldWidth , oldHeight);
			}
		}
		
	}

	@Override
	protected void onDraw(Canvas canvas) {
		super.onDraw(canvas);
		
		Drawable mDrawable = getDrawable();
		if (mDrawable == null)
		{
			return;
		}
        
        if (mDrawable.getIntrinsicWidth() == 0 || mDrawable.getIntrinsicHeight() == 0) {
            return;     // nothing to draw (empty bounds)
        }
        
        if(null == maskBitmap)
        {
        	return;
        }
        
        int saveCount = canvas.getSaveCount();
        canvas.save();
        paint.setFilterBitmap(false);
        paint.setXfermode(mXfermode);
        canvas.drawBitmap(maskBitmap, null, mRoundRect, paint);
        paint.setXfermode(null);
        canvas.restoreToCount(saveCount);
	}
}



這裡主要是重用了ImageView,如果你想強制繪製的View為圓角或者圓形圖片,把程式碼中註釋的程式碼開啟即可

	private void initObjectAttribute()
	{
		mBitmapPaint.setAntiAlias(true);
//		if(getScaleType() != ScaleType.CENTER_CROP)
//		{
//			setScaleType(ScaleType.CENTER_CROP);
//		}
	}

知識點不是很難,程式碼淺顯易懂,當然最好去熟讀一下ImageView的原始碼. 

原始碼獲取地址: