Android自定义控件总结

       Android 为我们提供了丰富的UI组件,同时也提供了方便的扩展方法,通过继承Android的系统组件,可以方便的扩展现有功能,本文总结下我的自定义控件学习历程。


首先从最简单的画个圆开始,自定一个控件,显示一个蓝色的圆形,由于不需要扩展功能,所以新建一个类继承view,控件的绘制需要覆写onDraw()函数来绘制View的显示内容,重写类的构造方法,初始化Paint(相当于画笔)


public class myView extends View {
    private float radius = 50;
    private Paint mPaint;
    public myView(Context context) {
        super(context);
        init();
    }

    public myView(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        init();
    }

    public myView(Context context, AttributeSet attrs) {
        super(context, attrs);
        init();
    }

    private void init(){
        mPaint = new Paint();
        mPaint.setColor(Color.BLUE);		//设置画笔颜色
    }

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        int width = getWidth();		//获取空间的宽高,以空间中心为圆心,以radius为半径画圆
        int height = getHeight();
        canvas.drawCircle(width/2,height/2,radius,mPaint);
    }
}


在xml界面布局文件中加入自定义的控件,需要指明控件的完整包名:

<my.project.notificationtest.myView
        android:layout_width="match_parent"
        android:layout_height="100" />


运行效果如下:



当改变控件的宽高属性时,你会发现“wrap_content”和“match_content”绘制出来的圆形是一样的,都是按照“match_parent”的宽高来进行绘制的,实际上Android在绘制View前,必须要对View进行测量,即需要告诉系统画一个多大的View,Android系统为我们提供了三种测量模式:EXACTLY、AT_MOST、UNSPECIFIED:


EXACTLY:精准值模式,当控件layout_width属性或layout_height属性指定为具体数值或者为match_parent(View父控件的大小)时,使用EXACTLY模式,例如上面蓝色的圆测量的大小使用的是这种模式,使用不同数值,圆心位置也会发生变化。


AT_MOST:最大值模式,当控件的layout_width或layout_height属性指定为wrap_content时,控件大小随着子控件内容变化而变化,控件的尺寸只要不超过父控件最大尺寸即可


UNSPECIFIED:不指定大小测量模式,通常在绘制自定义View时使用。


测量的过程在onMeasure()方法中进行,默认的测量模式是EXACTLY,不重写onMeasure()方法就只能使用EXACTLY模式,所以我们绘制的圆形在设置宽高属性为wrap_content时没有变化,由于并没有给出确切的宽高,所以EXACTLY使用了match_parent的大小来绘制圆形,所以我们重写onMeasure();通过判断测量模式,给出不同的测量值,将测量的大小传给setMeasureDimension()方法。

 @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        int widthMeasured,heightMeasured;
        widthMeasured = measureWidth(widthMeasureSpec);
        heightMeasured = measureHeight(heightMeasureSpec);
        setMeasuredDimension(widthMeasured,heightMeasured);
    }
    private int measureHeight(int measureSpec){
        int result = 0;
        int specMode = MeasureSpec.getMode(measureSpec);
        int specSize = MeasureSpec.getSize(measureSpec);

        if(specMode == MeasureSpec.EXACTLY){
            result = specSize;
        }else{
            result = 200;
            if(specMode == MeasureSpec.AT_MOST){
                result = Math.min(result,specSize);
            }
        }
        return result;
    }

    private int measureWidth(int measureSpec){
        int result = 0;
        int specMode = MeasureSpec.getMode(measureSpec);
        int specSize = MeasureSpec.getSize(measureSpec);

        if(specMode == MeasureSpec.EXACTLY){
            result = specSize;
        }else{
            result = 200;
            if(specMode == MeasureSpec.AT_MOST){
                result = Math.min(result,specSize);
            }
        }
        return result;
    }

现在设置我们自定义空间的大小属性为wrap_content时,圆形控件的大小将变为200*200,圆点中心也发生变化。



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值