自定义View二进阶

作者: summer_lz | 来源:发表于2017-05-08 15:32 被阅读8次

    分类与流程

    1. View的绘制流程

    自定义View绘制函数调用序列:


    1. 分类

    • 自定义View
      在没有现成的View,需要自己实现的时候,就使用自定义View,一般继承自View,SurfaceView或其他的View,不包含子View。
    • 自定义ViewGroup
      自定义ViewGroup一般是利用现有的组件根据特定的布局方式来组成新的组件,大多继承自ViewGroup或各种Layout,包含有子View。
    1. 重要函数

    2. 构造函数
    public void SloopView(Context context) {}
    public void SloopView(Context context, AttributeSet attrs) {}
    public void SloopView(Context context, AttributeSet attrs, int defStyleAttr) {}
    public void SloopView(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {}
    

    有三个参数的构造函数中第三个参数是默认的Style,这里的默认的Style是指它在当前Application或Activity所用的Theme中的默认Style,且只有在明确调用的时候才会生效,以系统中的ImageButton为例说明:

    public ImageButton(Context context, AttributeSet attrs) {
        //调用了三个参数的构造函数,明确指定第三个参数
        this(context, attrs, com.android.internal.R.attr.imageButtonStyle);
    }
    public ImageButton(Context context, AttributeSet attrs, int defStyleAttr) {
        //此处调了四个参数的构造函数,无视即可
        this(context, attrs, defStyleAttr, 0); 
    }
    

    注意:即使你在View中使用了Style这个属性也不会调用三个参数的构造函数,所调用的依旧是两个参数的构造函数。
    由于三个参数的构造函数第三个参数一般不用,暂不考虑,第三个参数的具体用法会在以后用到的时候详细介绍。
    排除了两个之后,只剩下一个参数和两个参数的构造函数,他们的详情如下:

    //一般在直接New一个View的时候调用。
    public void SloopView(Context context) {}
    //一般在layout文件中使用的时候会调用,关于它的所有属性(包括自定义属性)都会包含在attrs中传递进来。
    public void SloopView(Context context, AttributeSet attrs) {}
    
    1. onMeasure() 测量View大小

    View的大小不仅由自身所决定,同时也会受到父控件的影响,为了我们的控件能更好的适应各种情况,一般会自己进行测量。
    从onMeasure的两个参数中取出宽高的相关数据:

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        int widthsize  MeasureSpec.getSize(widthMeasureSpec);      //取出宽度的确切数值
        int widthmode  MeasureSpec.getMode(widthMeasureSpec);      //取出宽度的测量模式
        
        int heightsize  MeasureSpec.getSize(heightMeasureSpec);    //取出高度的确切数值
        int heightmode  MeasureSpec.getMode(heightMeasureSpec);    //取出高度的测量模式
    }
    

    从上面可以看出 onMeasure 函数中有 widthMeasureSpec 和 heightMeasureSpec 这两个 int 类型的参数, 毫无疑问他们是和宽高相关的, 但它们其实不是宽和高, 而是由宽、高和各自方向上对应的测量模式来合成的一个值
    测量模式一共有三种, 被定义在 Android 中的 View 类的一个内部类View.MeasureSpec中:
    |模式 |二进制数值| 描述
    |---------|-----------|------
    |UNSPECIFIED|00| 默认值,父控件没有给子view任何限制,子View可以设置为任意大小。
    |EXACTLY |01| 表示父控件已经确切的指定了子View的大小。
    |AT_MOST |10| 表示子View具体大小没有尺寸限制,但是存在上限,上限一般为父View大小。
    在int类型的32位二进制位中,31-30这两位表示测量模式,29~0这三十位表示宽和高的实际值,实际上如下:
    UNSPECIFIED | 00 | 000000000000000000001111011000
    注意:
    如果对View的宽高进行修改了,不要调用 super.onMeasure( widthMeasureSpec, heightMeasureSpec); **要调用 setMeasuredDimension( widthsize, heightsize); **

    1. onSizeChanged() 确定View大小

    View的大小不仅由View本身控制,而且受父控件的影响,所以我们在确定View大小的时候最好使用系统提供的onSizeChanged回调函数。

    @Override
        protected void onSizeChanged(int w, int h, int oldw, int oldh) {
            super.onSizeChanged(w, h, oldw, oldh);
        }
    
    1. onLaytout() 确定子View布局位置
    名称 说明 对应的函数
    l View左侧距父View左侧的距离 getLeft();
    t View顶部距父View顶部的距离 getTop();
    r View右侧距父View左侧的距离 getRight();
    b View底部距父View顶部的距离 getBottom();
    1. onDraw() 绘制

    相关文章

      网友评论

        本文标题:自定义View二进阶

        本文链接:https://www.haomeiwen.com/subject/puvmtxtx.html