自定义View入门

一、自定义View的基本步骤概括

  1. 自定义View的属性
  2. 在View子类的构造方法中获取自定义的属性
  3. 重写 onMesure()(非必须)
  4. 重写 onDraw()

二、自定义View的属性

  1. 在res/values/目录下创建xml文件用于定义View的属性


    
    
    
    
        
        
        
    

attr标签表示定义一个属性;format表示该属性的取值类型,有如下几种

string color demension integer
enum reference float boolean
fraction(百分比) flag - -

三、在View子类的构造方法中获取自定义的属性

  • 默认的布局文件调用的是两个参数的构造方法,在构造方法中还可以完成对Paint等的初始化工作。
//获取自定义的属性集
TypedArray typedArray = context.getTheme()
       .obtainStyledAttributes(attrs, R.styleable.MyTextView, defStyleAttr, 0);
//遍历每一个属性,并和所声明的属性绑定
for (int i = 0; i < typedArray.getIndexCount(); i++) {
    int attr = typedArray.getIndex(i);
    switch (attr) {
        case R.styleable.MyTextView_textColor:
             //绑定颜色并设置默认值为红色
             textColor = typedArray.getColor(attr, Color.RED);
             break;
        case R.styleable.MyTextView_textContent:
             textContent = typedArray.getString(attr);
             break;
        case R.styleable.MyTextView_textSize:
             //第二个参数的写法好像固定
             textSize = typedArray.getDimensionPixelSize(attr
                    , (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_SP
                            , 16, getResources().getDisplayMetrics()));
             break;
     }
}
//别忘了回收,虽然不知道是为什么
typedArray.recycle();

四、重写 onMesure()

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        //super.onMeasure(widthMeasureSpec, heightMeasureSpec);
        int width;
        int height;
        //获取宽高的定义方式,有MATCH_PARENT、WRAP_CONTENT、或具体的数值
        int widthMode = MeasureSpec.getMode(widthMeasureSpec);
        int heightMode = MeasureSpec.getMode(heightMeasureSpec);
        //获取设置的宽高
        int widthSize = MeasureSpec.getSize(widthMeasureSpec);
        int heightSize = MeasureSpec.getSize(heightMeasureSpec);

        //根据宽高的具体定义方式来确定具体的自定义View的宽高
        if (widthMode == MeasureSpec.EXACTLY) {
            width = widthSize;
        } else {
            width = 100;
        }

        if (heightMode == MeasureSpec.EXACTLY) {
            height = heightSize;
        } else {
            height = 100;
        }
        //设置宽高,不能忘
        setMeasuredDimension(width, height);
    }
        

注意:

  1. 当设置了明确的宽度和高度值时,获取到的widthSizeheightSize就是我们设置的结果,当设置WRAP_CONTENTMATCH_PARENT时系统测量的结果都是就是MATCH_PARENT
  2. MeasureSpec的specMode,一共三种类型:
    EXACTLY:表示设置了明确的值或者是MATCH_PARENT
    AT_MOST:表示子布局限制在一个最大值内,一般为WARP_CONTENT
    UNSPECIFIED:表示子布局想要多大就多大,很少使用
  3. onMeasure() 中的写法基本固定不变

五、重写onDraw()

    @Override
    protected void onDraw(Canvas canvas) {
        //super.onDraw(canvas);
        //在这里完成绘图工作
        //根具具体情况的不同而不同
    }

六、总结

自定义View的步骤很简单,就4步,然而要想实现或复杂或美观的自定义View还需不断努力,与君共勉!

你可能感兴趣的:(自定义View入门)