转载自:http://blog.csdn.NET/lmj623565791/article/details/24555655
自定义View实现圆角和圆形的效果:
核心代码
/**
* 根据原图和变长绘制圆形图片
*
* @param _bitmap
* @param _min
* @return
*/
private Bitmap createCircleImage(Bitmap _bitmap, int _min) {
Paint _paint = new Paint();
_paint.setAntiAlias(true);
Bitmap _target = Bitmap.createBitmap(_min, _min, Bitmap.Config.ARGB_8888);
//产生一个同样大小的画布
Canvas _canvas = new Canvas(_target);
//首先绘制圆形
_canvas.drawCircle(_min / 2, _min / 2, _min / 2, _paint);
//使用SRC_IN
_paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC_IN));
//绘制图片
_canvas.drawBitmap(_bitmap, 0, 0, _paint);
return _target;
}
其实主要靠:paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC_IN));这行代码,为什么呢,我给大家解释下,SRC_IN这种模式,两个绘制的效果叠加后取交集展现后图,怎么说呢,咱们第一个绘制的是个圆形,第二个绘制的是个Bitmap,于是交集为圆形,展现的是BItmap,就实现了圆形图片效果。圆角,其实就是先绘制圆角矩形,是不是很简单,以后别人再说实现圆角,你就把这一行代码给他就行了。
从Android的示例中,给大家证明一下:
下面有一张PorterDuff.Mode的16中效果图,咱们的只是其一:
源码咱们只关心谁先谁后绘制的:
canvas.translate(x, y);
canvas.drawBitmap(mDstB, 0, 0, paint);
paint.setXfermode(sModes[i]);
canvas.drawBitmap(mSrcB, 0, 0, paint);
paint.setXfermode(null);
canvas.restoreToCount(sc);
可以看出先绘制的Dst,再绘制的Src,最后的展示是SrcIn那个图:显示的区域是二者交集,展示的是Src(后者)。和咱们前面结论一致。效果16种,大家可以自由组合展示不同的效果。
一、自定义属性
<declare-styleable name="CustomCircleImage">
<attr name="borderRadius" format="dimension" />
<attr name="type">
<enum name="circle" value="0" />
<enum name="round" value="1" />
</attr>
<attr name="src" format="reference" />
</declare-styleable>
二、构造函数中获取属性
private int mType;
private static final int TYPE_CIRCLE = 0;
private static final int TYPE_ROUND = 1;
//图片
private Bitmap mBitmap;
//圆角的大小
private int mRadius;
//控件的宽度
private int mWidth;
//控件的高度
private int mHeight;
public CustomCircleImage(Context context) {
this(context, null);
}
public CustomCircleImage(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
public CustomCircleImage(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
initAttrs(context, attrs);
}
private void initAttrs(Context context, AttributeSet attrs) {
TypedArray _typedArray = context.obtainStyledAttributes(attrs, R.styleable.CustomCircleImage);
mRadius = (int) _typedArray.getDimension(R.styleable.CustomCircleImage_borderRadius, 10);
mType = _typedArray.getInt(R.styleable.CustomCircleImage_type, 0);
mBitmap = BitmapFactory.decodeResource(getResources(), _typedArray.getResourceId(R.styleable.CustomCircleImage_src, 0));
_typedArray.recycle();
}
三、onMeasure方法
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
mWidth = getOnMeasure(widthMeasureSpec);
mHeight = getOnMeasure(heightMeasureSpec);
setMeasuredDimension(mWidth, mHeight);
}
private int getOnMeasure(int _measureSpec) {
int _size = 100;
int _measureMode = View.MeasureSpec.getMode(_measureSpec);
int _measureSize = View.MeasureSpec.getSize(_measureSpec);
if (MeasureSpec.EXACTLY == _measureMode) {
_size = _measureSize;
}
return _size;
}
四、onDraw方法
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
switch (mType) {
//如果是绘制圆形
case TYPE_CIRCLE:
//长度如果不一致,则按照小的进行压缩
int _min = Math.min(mWidth, mHeight);
mBitmap = Bitmap.createScaledBitmap(mBitmap, _min, _min, false);
canvas.drawBitmap(createCircleImage(mBitmap, _min), 0, 0, null);
break;
case TYPE_ROUND:
canvas.drawBitmap(createRoundImage(mBitmap), 0, 0, null);
break;
}
}
/**
* 根据原图和变长绘制圆形图片
*
* @param _bitmap
* @param _min
* @return
*/
private Bitmap createCircleImage(Bitmap _bitmap, int _min) {
Paint _paint = new Paint();
_paint.setAntiAlias(true);
Bitmap _target = Bitmap.createBitmap(_min, _min, Bitmap.Config.ARGB_8888);
//产生一个同样大小的画布
Canvas _canvas = new Canvas(_target);
//首先绘制圆形
_canvas.drawCircle(_min / 2, _min / 2, _min / 2, _paint);
//使用SRC_IN
_paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC_IN));
//绘制图片
_canvas.drawBitmap(_bitmap, 0, 0, _paint);
return _target;
}
/**
* 根据原图添加圆角
*
* @param _bitmap
* @return
*/
private Bitmap createRoundImage(Bitmap _bitmap) {
Paint _paint = new Paint();
_paint.setAntiAlias(true);
Bitmap _target = Bitmap.createBitmap(mWidth, mHeight, Bitmap.Config.ARGB_8888);
//产生一个同样大小的画布
Canvas _canvas = new Canvas(_target);
RectF rect = new RectF(0, 0, _bitmap.getWidth(), _bitmap.getHeight());
_canvas.drawRoundRect(rect, mRadius, mRadius, _paint);
_paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC_IN));
_canvas.drawBitmap(_bitmap, 0, 0, _paint);
return _target;
}
五、布局中使用
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent">
<com.millet.myblogexercise.CustomCircleImage.CustomCircleImage
android:layout_width="match_parent"
android:layout_height="match_parent"
app:src="@mipmap/d"
app:type="circle" />
</RelativeLayout>