自定义控件一
自定义控件主要分成三种,1.完全自定义的控件;2.对当前的控件进行扩展;3.对当前的控件组合。
首先看第一种,完全自定义控件。以MyCircleImageView为例来说明自定义控件的创建方法。
先来看看MyCircleImageView 的效果,如下图所示,将一幅图片显示为圆形,并可以在边缘加上自己设定的颜色。
创建的过程大致分为以下几步:
1)创建MyCircleImageView类继承自View,并提供初始化函数
public class MyCircleImageView extends View{
public MyCircleImageView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
}
public MyCircleImageView(Context context, AttributeSet attrs) {
super(context, attrs);
//初始化
}
public MyCircleImageView(Context context) {
super(context);
}
}
2)自定义属性
在MyCircleView当中,设置了三个自定义的属性,分别是图片资源、边缘宽度、边缘颜色。
自定义属性写在attr.xml文件当中。
<declare-styleable name="MyCircleImageView">
<attr name="imageSrc" format="reference"/>
<attr name="borderWidth" format="dimension"/>
<attr name="borderColor" format="color"/>
</declare-styleable>3)在XML布局文件当中引入自定义属性
引入自定义属性的时候还必须加入自定义属性的命名空间,如下图所示
xmlns:custom="http://schemas.android.com/apk/res-auto"
然后就可以在view当中加入自定义属性了
<com.example.a.circleimage.MyCircleImageView
android:id="@+id/top"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="10dp"
android:layout_marginLeft="10dp"
custom:imageSrc="@drawable/mycatch"
custom:borderColor="@color/yellow"
custom:borderWidth="10dp"/>4)在代码当中读取XML文件当中的属性,初始化View
private void initAttrs(AttributeSet attrs){
if(attrs!=null){
TypedArray array = null;
try{
//读取属性
array = getContext().obtainStyledAttributes(attrs,R.styleable.MyCircleImageView);
this.mDrawable = array.getDrawable(R.styleable.MyCircleImageView_imageSrc);
this.mBorderWidth = array.getDimension(R.styleable.MyCircleImageView_borderWidth,0);
this.mBorderColor = array.getInt(R.styleable.MyCircleImageView_borderColor, 0);
this.mesureDrawable();
}catch (Exception e){
e.printStackTrace();
}
}
}5)测量View的尺寸
首先看一下设置View尺寸的三种模式,如下表所示
|
模式类型 |
说明 |
|
EXACTLY |
对应于match_parent或者具体的数值 |
|
AT_MOST |
对应于wrap_content |
|
UNSPECIFIED |
开发人员可以按照自己的意愿设置成任何大小,应用比较少 |
复写父类的onMeasure()方法,并且只有当模式为EXACTLY时,宽高才从MeasureSpec当中取,其他模式则宽高设置成图片的宽高。
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
//获取宽度的模式和大小
int widthMode = MeasureSpec.getMode(widthMeasureSpec);
int width = MeasureSpec.getSize(widthMeasureSpec);
//获取高度的模式和大小
int heightMode = MeasureSpec.getMode(heightMeasureSpec);
int height = MeasureSpec.getSize(heightMeasureSpec);
//设置view的宽和高
this.setMeasuredDimension(this.measureWidth(widthMode,width),this.measureHeight
(heightMode,height));
}
private int measureWidth(int mode ,int width){
switch (mode){
case MeasureSpec.UNSPECIFIED:
break;
case MeasureSpec.AT_MOST:
break;
case MeasureSpec.EXACTLY:
this.mWidth = width;
break;
}
return mWidth;
}
private int measureHeight(int mode , int height){
switch (mode){
case MeasureSpec.UNSPECIFIED:
break;
case MeasureSpec.AT_MOST:
break;
case MeasureSpec.EXACTLY:
this.mHeight = height;
break;
}
return mHeight;
}6)绘制View
复写ondraw()函数,将所得到的图片绘制成为圆形,并在外层添加颜色边缘。
@Override
protected void onDraw(Canvas canvas) {
if(mBitmap == null){
mBitmap = Bitmap.createScaledBitmap(drawableToBitmap(mDrawable),
getMeasuredWidth(),
getMeasuredHeight(),
true);
}
BitmapShader bitmapShader = new BitmapShader(mBitmap, Shader.TileMode.CLAMP,
Shader.TileMode.CLAMP);
this.mPaint.setShader(bitmapShader);
this.mPaint.setStyle(Paint.Style.FILL);
float x = mBitmap.getWidth()/2.0f;
float y = mBitmap.getHeight()/2.0f;
float radiu = Math.min(x,y);
canvas.drawCircle(x,y,radiu,mPaint);
if(this.mBorderColor!=0 && this.mBorderWidth!=0){
Paint borderPaint = new Paint();
borderPaint.setColor(this.mBorderColor);
borderPaint.setStyle(Paint.Style.STROKE);
borderPaint.setStrokeWidth(mBorderWidth);
borderPaint.setAntiAlias(true);
canvas.drawCircle(x,y,radiu+1-mBorderWidth/2.0f,borderPaint);
}
}完整的源码如下:
public class MyCircleImageView extends View {
private Paint mPaint;//画笔
private Drawable mDrawable;//图片
private int mWidth;//宽度
private int mHeight;//高度
private Bitmap mBitmap;
private int mBorderColor;//边框颜色
private float mBorderWidth;//边框宽度
public MyCircleImageView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
}
public MyCircleImageView(Context context, AttributeSet attrs) {
super(context, attrs);
this.initAttrs(attrs);
this.mPaint = new Paint();
this.mPaint.setAntiAlias(true);//抗锯齿
}
public MyCircleImageView(Context context) {
super(context);
}
private void initAttrs(AttributeSet attrs){
if(attrs!=null){
TypedArray array = null;
try{
//读取属性
array = getContext().obtainStyledAttributes(attrs,R.styleable.MyCircleImageView);
this.mDrawable = array.getDrawable(R.styleable.MyCircleImageView_imageSrc);
this.mBorderWidth = array.getDimension(R.styleable.MyCircleImageView_borderWidth,0);
this.mBorderColor = array.getInt(R.styleable.MyCircleImageView_borderColor, 0);
this.mesureDrawable();
}catch (Exception e){
e.printStackTrace();
}
}
}
//测量控件的大小
public void mesureDrawable(){
if(this.mDrawable!=null){
this.mHeight = this.mDrawable.getIntrinsicHeight();
this.mWidth = this.mDrawable.getIntrinsicWidth();
}
}
@Override
protected void onDraw(Canvas canvas) {
if(mBitmap == null){
mBitmap = Bitmap.createScaledBitmap(drawableToBitmap(mDrawable),
getMeasuredWidth(),
getMeasuredHeight(),
true);
}
BitmapShader bitmapShader = new BitmapShader(mBitmap, Shader.TileMode.CLAMP,
Shader.TileMode.CLAMP);
this.mPaint.setShader(bitmapShader);
this.mPaint.setStyle(Paint.Style.FILL);
float x = mBitmap.getWidth()/2.0f;
float y = mBitmap.getHeight()/2.0f;
float radiu = Math.min(x,y);
canvas.drawCircle(x,y,radiu,mPaint);
if(this.mBorderColor!=0 && this.mBorderWidth!=0){
Paint borderPaint = new Paint();
borderPaint.setColor(this.mBorderColor);
borderPaint.setStyle(Paint.Style.STROKE);
borderPaint.setStrokeWidth(mBorderWidth);
borderPaint.setAntiAlias(true);
canvas.drawCircle(x,y,radiu+1-mBorderWidth/2.0f,borderPaint);
}
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
//获取宽度的模式和大小
int widthMode = MeasureSpec.getMode(widthMeasureSpec);
int width = MeasureSpec.getSize(widthMeasureSpec);
//获取高度的模式和大小
int heightMode = MeasureSpec.getMode(heightMeasureSpec);
int height = MeasureSpec.getSize(heightMeasureSpec);
//设置view的宽和高
this.setMeasuredDimension(this.measureWidth(widthMode,width),this.measureHeight
(heightMode,height));
}
private int measureWidth(int mode ,int width){
switch (mode){
case MeasureSpec.UNSPECIFIED:
break;
case MeasureSpec.AT_MOST:
break;
case MeasureSpec.EXACTLY:
this.mWidth = width;
break;
}
return mWidth;
}
private int measureHeight(int mode , int height){
switch (mode){
case MeasureSpec.UNSPECIFIED:
break;
case MeasureSpec.AT_MOST:
break;
case MeasureSpec.EXACTLY:
this.mHeight = height;
break;
}
return mHeight;
}
//将drawable转换成bitmap
public Bitmap drawableToBitmap(Drawable drawable) {
Bitmap bitmap = Bitmap.createBitmap(
drawable.getIntrinsicWidth(),
drawable.getIntrinsicHeight(),
drawable.getOpacity() != PixelFormat.OPAQUE ? Bitmap.Config.ARGB_8888
: Bitmap.Config.RGB_565);
Canvas canvas = new Canvas(bitmap);
canvas.setBitmap(bitmap);
drawable.setBounds(0, 0, drawable.getIntrinsicWidth() ,drawable.getIntrinsicHeight());
drawable.draw(canvas);
return bitmap;
}
}



浙公网安备 33010602011771号