很多时候我们都需要使用到圆形的图像控件,比如头像之类的。如果是开发者自己设计界面的时候使用,取巧的方法就是让美工给你做一个圆形ICON,但很多时候是需要显示用户上传的图像,这时候做一个通用的圆形图像控件是有必要的,那如何实现呢?
Android图像控件一般是使用ImageView,那么我们这个自定义CircleView的圆形图像控件就继承于该控件。
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.PorterDuff;
import android.graphics.PorterDuffXfermode;
import android.graphics.drawable.BitmapDrawable;
import android.util.AttributeSet;
import android.widget.ImageView;
/**
* Helen 2015-05-13
*/
public class CircleView extends ImageView{
private Bitmap mSrcBitmap;//ImageView设置的图像资源文件
private Bitmap mOut;
private Paint mPaint;//画笔
public CircleView(Context context) {
super(context);
init();
}
public CircleView(Context context, AttributeSet attrs) {
super(context, attrs);
init();
}
public CircleView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
init();
}
private void init(){
//setLayerType(LAYER_TYPE_SOFTWARE,null);//禁用硬件加速
mSrcBitmap=((BitmapDrawable)getDrawable()).getBitmap();
mOut=Bitmap.createBitmap(mSrcBitmap.getWidth(),mSrcBitmap.getHeight(), Bitmap.Config.ARGB_8888);
mPaint=new Paint(Paint.ANTI_ALIAS_FLAG);
Canvas canvas=new Canvas(mOut);
//Dst
canvas.drawCircle(mOut.getWidth() / 2, mOut.getHeight() / 2,mOut.getWidth() / 2, mPaint);
mPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC_IN));
//Src
canvas.drawBitmap(mSrcBitmap,0,0,mPaint);
mPaint.setXfermode(null);
}
@Override
protected void onDraw(Canvas canvas) {
canvas.drawBitmap(mOut,0,0,null);
}
}
实现的方法是使用Paint的Xfermode属性。需要了解的请戳这里
布局文件如下activity_main.xml
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="@mipmap/test"
android:layout_above="@+id/view"
android:layout_centerHorizontal="true"
android:layout_marginBottom="64dp" />
<com.hbase.view.CircleView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerInParent="true"
android:src="@mipmap/test"
android:id="@+id/view" />
RelativeLayout>
效果图:
上面是原图,下面是圆形图像控件。
但是你会发现,是这张图片切得刚好大小,我们换张大点的试试。
效果并不是我们所想要的。
那么如何改进呢?我们是否可以根据控件的大小来显示图像并将图像进行缩放呢?
改进后:
package com.hbase.view;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.PorterDuff;
import android.graphics.PorterDuffXfermode;
import android.graphics.drawable.BitmapDrawable;
import android.graphics.drawable.Drawable;
import android.util.AttributeSet;
import android.widget.ImageView;
/**
* Helen 2015-05-13
*/
public class CircleView extends ImageView{
private Bitmap mSrcBitmap;//ImageView设置的图像资源文件
private Bitmap mOut;
private Paint mPaint;//画笔
public CircleView(Context context) {
super(context);
//init();
}
public CircleView(Context context, AttributeSet attrs) {
super(context, attrs);
//init();
}
public CircleView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
//init();
}
private void init(){
//setLayerType(LAYER_TYPE_SOFTWARE,null);//禁用硬件加速
Drawable d=getDrawable();
if(d==null) return;
mSrcBitmap=((BitmapDrawable)d).getBitmap();
//mOut=Bitmap.createBitmap(mSrcBitmap.getWidth(),mSrcBitmap.getHeight(), Bitmap.Config.ARGB_8888);
mSrcBitmap=Bitmap.createScaledBitmap(mSrcBitmap,getWidth(),getHeight(),true);//设置缩放
mOut=Bitmap.createBitmap(getWidth(), getHeight(), Bitmap.Config.ARGB_8888);
mPaint=new Paint(Paint.ANTI_ALIAS_FLAG);
Canvas canvas=new Canvas(mOut);
//Dst
canvas.drawCircle(getWidth() / 2, getHeight() / 2,getWidth() / 2, mPaint);
//canvas.drawCircle(mOut.getWidth() / 2, mOut.getHeight() / 2,mOut.getWidth() / 2, mPaint);
mPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC_IN));
//Src
canvas.drawBitmap(mSrcBitmap,0,0,mPaint);
mPaint.setXfermode(null);
}
@Override
protected void onDraw(Canvas canvas) {
//只有在onDraw中才能获取到控件的宽高
init();
canvas.drawBitmap(mOut,0,0,null);
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
int width=Math.min(getMeasuredHeight(),getMeasuredWidth());
//因为是要圆形图像,所以将控件的宽高设置为一样
setMeasuredDimension(width,width);
}
}