自定义控件一

        自定义控件主要分成三种,1.完全自定义的控件;2.对当前的控件进行扩展;3.对当前的控件组合。

        首先看第一种,完全自定义控件。以MyCircleImageView为例来说明自定义控件的创建方法。

先来看看MyCircleImageView 的效果,如下图所示,将一幅图片显示为圆形,并可以在边缘加上自己设定的颜色。

S70108-123602

        创建的过程大致分为以下几步:

        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布局文件当中引入自定义属性

        引入自定义属性的时候还必须加入自定义属性的命名空间,如下图所示

Catch

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;

    }
}
posted @ 2017-01-08 13:30  黄大仙爱编程  阅读(115)  评论(0编辑  收藏  举报