Android自定义控件

来源:互联网 发布:windows 执行dll文件 编辑:程序博客网 时间:2024/06/05 20:14

自定义控件

近期写了一些,但是都没整理,抓点时间整理出来

1. View

基本流程:

> 1.构造函数:View的初始化> 2.onMeasure:测量View大小> 3.onSizeChanged:确定View大小(这一步并不关键)> 4.onLayout:确定子View布局(自定义View包含子View时有用)> 5.onDraw:实际绘制内容> 6.监听接口:控制View或监听View某些状态。

1. 构造函数:

  • 代码:

    public CustomView(Context context) {    this(context, null);}public CustomView(Context context, AttributeSet attrs) {    this(context, attrs, 0);}public CustomView(Context context, AttributeSet attrs, int defStyleAttr) {    super(context, attrs, defStyleAttr);    //1.初始化    mPaint = new Paint();    mPaint.setAntiAlias(true);    mPaint.setColor(getResources().getColor(R.color.colorPrimaryDark));}
  • 一个参数:在java中new时被使用。

  • 两个参数:在XML中进行定义时被调用,第二个参数代表xml中定义的属性

  • 三个参数:能够添加一个style。

    使用this,以及默认属性将三个构造进行传递,最终被使用的都是三个参数的构造,而在进行初始化时也只需要在三个参数的构造函数中进行即可。


2.onMeasure:

  1. onMeasure基本流程:
ViewRoot -> performTraversals -> measure -> onMeasure
  1. View显示有两个前提,一是有自身的宽高属性,二是在整体中的位置,第一个宽高属性由onMeasure进行测量,而本身我们在xml中定义的宽高首先是由其对应的父控件决定,其次再由自己决定,所以需要进行这样一个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);    }
  1. 分析:
    onMeasure中有两个参数,这两个参数其实不是表面上的意义,其本身由一个32位的值组成,第30和31位表示其测量模式,0到29表示其真是的宽高值,如下表:

    模式名称 模式数值 实际数值 对应的值 UNSPECIFIED 00 000000000000000000001111011000 自定义时使用 EXACTLY 01 000000000000000000001111011000 如50dp AT_MOST 10 000000000000000000001111011000 wrap_content
  2. 模式:
    测量模式有三种,是在View类中的一个内部类进行定义的:View.MeasureSpec:

    • UNSPECIFIED:以00为默认值,父控件没有给子view任何的限制,可以设置为任意大小。
    • EXACTLY:以01为默认值,父控件已经确切的指定了子view的大小。
    • AT_MOST:以10位默认值,大小没有尺寸限制,上限为父View的大小,即wrap_content。
  3. measure:

    1. measure是每个view中一定存在一个必调的方法,measure(widthMeasureSpec,heightMeasureSpec) ,它调用onMeasure(int,int)
    2. 是用于确定视图的高度和宽度的规格和大小
    3. 未复写该方法时调用,getDefaultSize方法进行测量

    从其内部实现看,视图大小的控制是由父视图,布局文件,以及视图本身共同完成的,父视图会提供给 子视图参考的大小,而开发人员可以在XML文件中指定视图大小,然后视图本身会对最终的大小进行排版。


3. onSizeChanged:

  1. 这个函数在视图大小发生改变时调用。

  2. 在测量完View并使用setMeasuredDimension函数之后View的大小基本上已经确定了,但View的大小不仅由View本身控制,还受父控件的影响,所以我们在确定View大小的时候最好使用系统提供的onSizeChanged回调函数。

    @Overrideprotected void onSizeChanged(int w, int h, int oldw, int oldh) {    super.onSizeChanged(w, h, oldw, oldh);}
    • 其四个参数分别为 宽度,高度,上一次宽度,上一次高度。
  3. 生命周期

    从上图中可以看出,onSizeChanged方法比onMeasure进行的少,而当我们在需要获取宽高等操作时,可以不再放在onMeasure中进行,使用onSizeChanged也能够提高一些效率。

  4. 插入一条:getWidth和getMeasureWidth基本相同,前者在layout之后获取,后者在measure后获取到, 后者的值通过setMeasureDimension设置,前者由本视图通过右边坐标减左边坐标计算的。


4. onLayout:

  1. onLayout基本流程:
ViewRoot -> performTraversals -> layout-> onLayout
  1. layout:
    • 参数:int类型,分别为相对当前父视图的左,上,右,下的值。
    • 在其内部的过程:
      1. 判断视图大小是否发生过变化,以确定有没有必要对当前视图进行重绘,同时也将传递过来的四个参数分别复制给成员变量型的左上右下。
      2. 然后进入onLayout进行定位,且默认该方法内部实现为空。因为定位其位置的操作是又布局完成,是由其父布局决定他的显示位置。而在ViewGroup中的onLayout是一个抽象方法,即表明在自定义或是xml中都需要我们手动对其覆写和定义的。

5. onDraw:

  1. onDraw的基本流程:
ViewRoot -> new Canvas -> draw -> 四个关键步骤
  1. 绘制的四个关键步骤:

    其实有6步,但另外两步使用的很少,忽略了。

    1. 画背景:
      如果需要的话:得到mBGDrawable对象,然后根据layout过程确定的视图位置来设置背 景的绘制区域,然后调用Drawable的draw方法来完成背景的绘制工作,mBGDrawable由布局文件中 的android:background来的,也可以通过setBackgroundColor和setBackgroundResource 来赋值获取
    2. 绘制视图内容:
      即onDraw(canvas)。内部实现为空,由子类实现,View内部不会进行内容的绘制,而非大部分我们是由布局文件中的定义进行确定内容,之后由View进 行绘制,如TextView和ImageView,内部通过Canvas进行绘制。自定义中需要我们进行重写。

    3. 对当前视图的所有子视图进行绘制,如果没有子视图,就不需要进行绘制。dispatchDraw内部实现依旧为空。

    4. 对视图的滚动条进行绘制。

    onDraw部分的内容很多,这里简略讲,会单开一章介绍的。


未完待续。。。

0 0