美文网首页
自定义View(一) 自定义View的概述

自定义View(一) 自定义View的概述

作者: 笔墨Android | 来源:发表于2017-12-21 16:40 被阅读0次

    不怕跌倒,所以飞翔

    自定义View概述

    1.自定义View分类

    • 自定义View 直接继承View主要是绘制
    • 自定义ViewGroup 继承ViewGroup主要是计算所有子控件的大小和位置
    • 继承相应的View,如TextView,Button,LinearLayout等

    2.自定义View的流程

    自定义view的绘制流程

    3.相应的构造函数:

    当你继承View会有4个相应的构造方法:

    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) {}
    
    • 第一个是new对象的时候调用的方法
    • 第二个是在布局文件中使用的时候调用的方法
    • 第三个是设置主题的时候调用的方法,这里你可以指定,也可以写死
    • 第四个是在21版本新添加的方法,暂且不论

    4.View的测量(onMeasure)

    这个方法的作用是用来测量View的相应的方法,基本上有固定的模板代码,其实就是计算整个View占用的大小

        @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);
    
            int realWidth;/*真是的宽度*/
            int realHeight;/*真是的高度*/
    
            if (widthMode == MeasureSpec.EXACTLY) {
                realWidth = width;
            } else if (widthMode == MeasureSpec.AT_MOST) {
                realWidth = 500;/*这里是定义的最大值*/
            } else {
                realWidth = 500;/*未知宽度的时候*/
            }
    
            if (heightMode == MeasureSpec.EXACTLY) {
                realHeight = height;
            } else if (heightMode == MeasureSpec.AT_MOST) {
                realHeight = 500;/*这里是定义的最大值*/
            } else {
                realHeight = 500;/*未知高度的时候*/
            }
    
            setMeasuredDimension(realWidth, realHeight);
        }
    

    这里记住相应的三种状态:

    • AT_MOST 最大值,但是不会超过父容器
    • EXACTLY 具体指,指定了具体的大小
    • UNSPECIFIED 未知大小,这里是父容器没有指定相应的大小(其实上面的两种状态考虑到的话就可以不用去设置这个了)

    上面这个例子基本上就是onMeasure的模板代码,但是有的控件涉及到重绘界面,那么只要把相应的realWidth和realHeight写成动态的就可以了.但是基本的逻辑是不会改变的...

    5.View的绘制(onDraw)

        @Override
        protected void onSizeChanged(int w, int h, int oldw, int oldh) {
            super.onSizeChanged(w, h, oldw, oldh);
        }
    

    这个方法主要涉及到Canvas的相应操作,后面会单提出来去讲.其实就是相应的API的一些绘制操作.

    6.View大小的改变操作(onSizeChanged)

        @Override
        protected void onSizeChanged(int w, int h, int oldw, int oldh) {
            super.onSizeChanged(w, h, oldw, oldh);
        }
    

    其实这个方法是确定View大小的方法,但是如果你调用** requestLayout();**方法的时候是强制重绘,整个绘制流程都会重新走一遍,也就是说onMeasue(),onSizeChanged()和onDraw()都会重新执行,这样也就达到了相应的改变View的效果了,这种一般都是和手势有关的View.

    7.子View位置的确定(onLayout)

    确定布局的函数是onLayout,它用于确定子View的位置,在自定义ViewGroup中会用到,他调用的是子View的layout函数。


    View位置的确定

    其实这里面只有一张图的事情,理解了这张图就能更好的设置相应的位置了.

    8.相应的属性值

    其实这部分的代码也是相应的模板代码,只要记住了就行.

    • 在相应的res文件夹下创建一个attrs的xml文件,用来实现自定义View的style(也就是可以使用的属性)
          <declare-styleable name="HorizontalEditItemView">
              <attr name="title" format="string" />
              <attr name="etHint" format="string" />
          </declare-styleable>
      
      

    这里的属性你可以随意定义,只要符合你的习惯就行

    • 在自定义View中使用该属性
             TypedArray typedArray = context.obtainStyledAttributes(attrs, R.styleable.HorizontalEditItemView);
              String title = typedArray.getString(R.styleable.HorizontalEditItemView_title);
              String etHint = typedArray.getString(R.styleable.HorizontalEditItemView_etHint);
                
              typedArray.recycle();
      

    这里使用完TypedArray之后一定要进行释放.


    概述的内容就这么多,其实写的挺晦涩的,这里讲的太仔细的话,效果还是一样的,只有你真正的去使用,才能去理解.这里只是一个概述,后面的文章会在使用的时候更加完善的讲解!

    参考文献:
    GcsSloop的自定义系类文章
    Carson_Ho关于自定义的文章

    相关文章

      网友评论

          本文标题:自定义View(一) 自定义View的概述

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