在Android 开发过程中我们可能遇到比较特殊的需求,我们需要自定义View, 来满足需求。
自定义View的三部曲:1. 首先是自定义View 的属性,2. onMeasure()方法, 3. onDraw() 方法
本文还结合UIL(图片框架,显示本地和网络加载) 这里不详解这个框架,就是使用它完成相应的功能。后续会出文章就行讲解。
我以创建圆形头像为基础来讲解。我参考了菜鸟窝的视频;
我们先看看图吧!
第一个是显示本地资源图片, 第二个是使用ImageLoad加载了网络图片。
ok,开始我们的代码
1. 属性的创建:
首先在res/values文件目录下创建一个attrs.xml文件, 在创建如下代码。
其中<attr>标签的format属性值代表属性的类型,这个类型值一共有10种,分别是:reference,float,color,dimension,boolean,string,enum,integer,fraction,flag
具体情况请看该博客详解:http://blog.csdn.net/sunny2come/article/details/6996943
<?xml version="1.0" encoding="utf-8"?> <resources> <declare-styleable name="CiecleImageView"> <attr name="outCiecleColor" format="color"></attr> <attr name="outCiecleWidth" format="dimension"></attr> </declare-styleable> </resources>
2. onMeasure()方法:
在开始写这个之前我们需要了解一下必要属性
MeasureSpec的三种模式:
EXACTLY : 表示设置了MATCH_PARENT或者一个准确的数值,含义是父布局要给子布局一个确切的大小。
AT_MOST : 表示子布局将被限制在一个最大值之内,通常是子布局设置了wrap_content。
UNSPECIFIED : 表示子布局想要多大就可以要多大,注:我基本上没有用过
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
int width = measureWidthOrHeight(widthMeasureSpec);
int height = measureWidthOrHeight(heightMeasureSpec);
mViewWidth = width - (mOutCieCleWidth * 2);
mViewHeight = height - (mOutCieCleWidth * 2);
// 传给系统测量参数
setMeasuredDimension(width, height);
}
其中 measureWidthOrHeight 是一个自定的方方用于计算高宽
3. ondraw()方法绘制出来:
其中 createCiecleBitamp 用于画出一个圆形的bitmap对象。<span style="font-size: 24px;"> </span><span style="font-size:12px;">@Override protected void onDraw(Canvas canvas) { // 加载图片 loadimg(); if(mImage != null){ int min = Math.min(mViewHeight, mViewWidth); int ciecleCenter = min/2; // 半径 mImage = Bitmap.createScaledBitmap(mImage, min, min, false); // 画出一个圆 canvas.drawCircle(ciecleCenter + mOutCieCleWidth, ciecleCenter + mOutCieCleWidth, ciecleCenter + mOutCieCleWidth, mPaintBorder); // 画出一个圆形的Bitmap canvas.drawBitmap(createCiecleBitamp(mImage, min), mOutCieCleWidth, mOutCieCleWidth, null); } }</span>
接下来看看,CieCleImageView 的完整代码了 (注: 我将这个头像单独写成一个Library的 module:如何创建请参考我的另外文章:Android Studio 中创建一个Library 的module 和导入一个Library项目)
该代码是写在了headimglibrary 模块里面,最后我会附上工程项目。
CiecleImageView.java 代码
import android.content.Context; import android.content.res.TypedArray; 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.drawable.BitmapDrawable; import android.util.AttributeSet; import android.widget.ImageView; /** * @author zzf * @data 16/10/1. * @Description */ public class CieCleImageView extends ImageView { // 外圆的颜色(默认为白色) private int mOutCieCleColor = Color.WHITE; // 外圆的宽度 private int mOutCieCleWidth; // 背景的画笔 private Paint mPaintBorder; // 控件的高宽 private int mViewHeight; private int mViewWidth; // 创建bitmap对象 private Bitmap mImage; public CieCleImageView(Context context) { super(context); initAttrs(context, null); } public CieCleImageView(Context context, AttributeSet attrs) { super(context, attrs); initAttrs(context, attrs); } public CieCleImageView(Context context, AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); initAttrs(context, attrs); } /** * 初始化属性 * @param context * @param attrs */ private void initAttrs(Context context, AttributeSet attrs) { if(attrs != null){ TypedArray array = context.obtainStyledAttributes(attrs, R.styleable.CiecleImageView); int len = array.length(); for (int i = 0; i < len; i++){ int attr = array.getIndex(i); if (attr == R.styleable.CiecleImageView_outCiecleColor) { this.mOutCieCleColor = array.getColor(attr, Color.WHITE); } else if (attr == R.styleable.CiecleImageView_outCiecleWidth) { this.mOutCieCleWidth = (int)array.getDimension(attr,5); } } } // 创建画笔 mPaintBorder = new Paint(); // 设置画笔的颜色 mPaintBorder.setColor(mOutCieCleColor); // 设置画笔为抗锯齿 mPaintBorder.setAntiAlias(true); } @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { int width = measureWidthOrHeight(widthMeasureSpec); int height = measureWidthOrHeight(heightMeasureSpec); mViewWidth = width - (mOutCieCleWidth * 2); mViewHeight = height - (mOutCieCleWidth * 2); // 传给系统测量参数 setMeasuredDimension(width, height); } /** * 测量 * MeasureSpec的三种模式: * EXACTLY: 表示的我们设置了Match_parent或者一个准确的数值,含义是父布局要给子布局一个确切的大小. * AT_MOST: 表示子布局将限制在一个最大值之内,通常是子布局设置了wrap_content * UNSPECIFIED:表示子布局想要多大就可以要多大,通常出现在AdapterView中item的heightMode中。 * * @param measureSpec * @return */ private int measureWidthOrHeight(int measureSpec) { int result = 0; int mode = MeasureSpec.getMode(measureSpec); int size = MeasureSpec.getSize(measureSpec); if(mode == MeasureSpec.EXACTLY){ // 表示我们设置了match_parent,或者是设置了准确的值 result = size; }else{ result = mViewWidth; } return result; } @Override protected void onDraw(Canvas canvas) { // 加载图片 loadimg(); if(mImage != null){ int min = Math.min(mViewHeight, mViewWidth); int ciecleCenter = min/2; // 半径 mImage = Bitmap.createScaledBitmap(mImage, min, min, false); // 画出一个圆 canvas.drawCircle(ciecleCenter + mOutCieCleWidth, ciecleCenter + mOutCieCleWidth, ciecleCenter + mOutCieCleWidth, mPaintBorder); // 画出一个圆形的Bitmap canvas.drawBitmap(createCiecleBitamp(mImage, min), mOutCieCleWidth, mOutCieCleWidth, null); } } /** * 加载图片 */ private void loadimg() { BitmapDrawable bitmapDrawable = (BitmapDrawable) this.getDrawable(); if(bitmapDrawable != null){ mImage = bitmapDrawable.getBitmap(); } } /** * 返回一个圆形的bitmap * @param mImage * @param min * @return */ private Bitmap createCiecleBitamp(Bitmap mImage, int min) { Bitmap bitmap = null; Paint paint = new Paint(); paint.setAntiAlias(true); bitmap = Bitmap.createBitmap(min, min, Bitmap.Config.ARGB_8888); // 创建一个画布 Canvas canvas = new Canvas(bitmap); canvas.drawCircle(min/2, min/2, min/2, paint); paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC_IN)); // 在画一个bitmap canvas.drawBitmap(mImage, 0, 0, paint); return bitmap; } /** * 设置外圆的颜色, 代码中定义 * @param color */ public void setOutCieCleColor(int color){ if(mPaintBorder != null){ mPaintBorder.setColor(color); } // 刷新视图 this.invalidate(); } /** * 外圆的宽度 * @param outCiecleWidth */ public void setOutCiecleWidth(int outCiecleWidth){ this.mOutCieCleWidth = outCiecleWidth; this.invalidate(); } }
到此就结束了:
下面最附上下载的地址:http://download.csdn.net/detail/zhongzunfa/9644751