基础篇——View和ViewGroup的区别

写代码的四点:

  1. 明确需求。要做什么?
  2. 分析思路。要怎么做?(1,2,3……)
  3. 确定步骤。每一个思路要用到哪些语句、方法和对象
  4. 代码实现。用具体的语言代码将思路实现出来。

学习新技术的四点:

  1. 该技术是什么?

  2. 该技术有什么特点?(使用需注意的方面)

  3. 该技术怎么使用?(写Demo)

  4. 该技术什么时候用?(在Project中的使用场景 )
    ----------------------早计划,早准备,早完成。-------------------------
    Android的UI界面都是由View和ViewGroup及其派生类组合而成的。其中,View是所有UI组件的基类,而ViewGroup是容纳View及其派生类的容器,ViewGroup也是从View派生出来的。一般来说,开发UI界面都不会直接使用View和ViewGroup(自定义控件的时候使用),而是使用其派生类。

    下图:UI布局的层次结构。
    image

View和ViewGroup的区别:

可以从两方面来说:

    一.事件分发方面的区别;

    二.UI绘制方面的区别;

事件分发方面的区别:

事件分发机制主要有三个方法:dispatchTouchEvent()、onInterceptTouchEvent()、onTouchEvent()

  1. ViewGroup包含这三个方法,而View则只包含dispatchTouchEvent()、onTouchEvent()两个方法,不包含onInterceptTouchEvent()。

  2. 触摸事件由Action_Down、Action_Move、Action_Up组成,一次完整的触摸事件,包含一个Down和Up,以及若干个Move(可以为0);

  3. 在Action_Down的情况下,事件会先传递到最顶层的ViewGroup,调用ViewGroup的dispatchTouchEvent(),①如果ViewGroup的onInterceptTouchEvent()返回false不拦截该事件,则会分发给子View,调用子View的dispatchTouchEvent(),如果子View的dispatchTouchEvent()返回true,则调用View的onTouchEvent()消费事件。②如果ViewGroup的onInterceptTouchEvent()返回true拦截该事件,则调用ViewGroup的onTouchEvent()消费事件,接下来的Move和Up事件将由该ViewGroup直接进行处理。

  4. 当某个子View的dispatchTouchEvent()返回true时,会中止Down事件的分发,同时在ViewGroup中记录该子View。接下来的Move和Up事件将由该子View直接进行处理。

  5. 当ViewGroup中所有子View都不捕获Down事件时,将触发ViewGroup自身的onTouch();触发的方式是调用super.dispatchTouchEvent函数,即父类View的dispatchTouchEvent方法。在所有子View都不处理的情况下,触发Acitivity的onTouchEvent方法。

  6. 由于子View是保存在ViewGroup中的,多层ViewGroup的节点结构时,上层ViewGroup保存的会是真实处理事件的View所在的ViewGroup对象。如ViewGroup0——ViewGroup1——TextView的结构中,TextView返回了true,它将被保存在ViewGroup1中,而ViewGroup1也会返回true,将被保存在ViewGroup0中;当Move和Up事件来时,会先从ViewGroup0传递到ViewGroup1,再由ViewGroup1传递到TextView,最后事件由TextView消费掉。

  7. 子View可以调getParent().requestDisallowInterceptTouchEvent(),请求父ViewGroup不拦截事件。

UI绘制方面的区别:

UI绘制主要有五个方法:onDraw(),onLayout(),onMeasure(),dispatchDraw(),drawChild()

  1. ViewGroup包含这五个方法,而View只包含onDraw(),onLayout(),onMeasure()三个方法,不包含dispatchDraw(),drawChild()。

  2. 绘制流程:onMeasure(测量)——》onLayout(布局)——》onDraw(绘制)。

  3. 绘制按照视图树的顺序执行,视图绘制时会先绘制子控件。如果视图的背景可见,视图会在调用onDraw()之前调用drawBackGround()绘制背景。强制重绘,可以使用invalidate();

  4. 如果发生视图的尺寸变化,则该视图会调用requestLayou(),向父控件请求再次布局。如果发生视图的外观变化,则该视图会调用invalidate(),强制重绘。如果requestLayout()或invalidate()有一个被调用,框架会对视图树进行相关的测量、布局和绘制。

注意:视图树是单线程操作,直接调用其它视图的方法必须要在UI线程里。跨线程的操作必须使用Handler。

  1. onLayout():对于View来说,onLayout()只是一个空实现;而对于ViewGroup来说,onLayout()使用了关键字abstract的修饰,要求其子类必须重载该方法,目的就是安排其children在父视图的具体位置。

  2. draw过程:drawBackground()绘制背景——》onDraw()对View的内容进行绘制——》dispatchDraw()对当前View的所有子View进行绘制——》onDrawScrollBars()对View的滚动条进行绘制。

image
方法说明:

  1. onDraw(Canvas canvas):UI绘制最重要的方法,用于UI重绘。这个方法是所有View、ViewGroup及其派生类都具有的方法。自定义控件时,可以重载该方法,并在内容基于canvas绘制自定义的图形、图像效果。

  2. onLayout(boolean changed, int left, int top, int right, int bottom):布局发生变化时调用此方法。这个方法是所有View、ViewGroup及其派生类都具有的方法。自定义控件时,可以重载该方法,在布局发生改变时实现特效等定制处理。

  3. onMeasure(int widthMeasureSpec, int heightMeasureSpec):用于计算自己及所有子对象的大小。这个方法是所有View、ViewGroup及其派生类都具有的方法。自定义控件时,可以重载该方法,重新计算所有对象的大小。 MeasureSpec包含了测量的模式和测量的大小,通过MeasureSpec.getMode()获取测量模式,通过MeasureSpec.getSize()获取测量大小。mode共有三种情况: 分别为MeasureSpec.UNSPECIFIED( View想多大就多大), MeasureSpec.EXACTLY(默认模式,精确值模式:将layout_width或layout_height属性指定为具体数值或者match_parent。), MeasureSpec.AT_MOST( 最大值模式:将layout_width或layout_height指定为wrap_content。)。

  4. dispatchDraw(Canvas canvas):ViewGroup及其派生类具有的方法,主要用于控制子View的绘制分发。自定义控件时,重载该方法可以改变子View的绘制,进而实现一些复杂的视效。

  5. drawChild(Canvas canvas, View child, long drawingTime):ViewGroup及其派生类具有的方法,用于直接绘制具体的子View。自定义控件时,重载该方法可以直接绘制具体的子View。

转自基础篇——View和ViewGroup的区别

原文地址:https://www.cnblogs.com/sishuiliuyun/p/15772241.html