View原理(一)———View和ViewGroup概念

概念

View是用来描述屏幕上的某一块矩形区域。两个特征: 1.View一定是矩形的,和像素排列有关系,但绝不会是除矩形之外的其他任何形状。 2.仅仅用于描述屏幕上的一块区域,与区域内部具体要显示的内容没有任何关系。 拓展:图片和View一样,也仅仅是矩形的。

和Activity的区别

  • 我们之前学习过的Android的四大组件Activity是四大组件中唯一一个用来和用户进行交互的组件,可以说Activity就是Android中的视图层(MVC中V层)
  • 如果再细化,Activity相当于视图层中的控制层(MVC中V层中的C层)。是用来管理和控制View的,真正用来显示和处理事件的实际上是View。
  • 每个Activity内部都有个Window对象。Window对象包含了一个DecorView(实际上就是一个FrameLayout)。我们通过setContentView()方法给Activity设置显示的View实际上都是加到了DecorView中。

    View种类

    android提供了种类丰富的View来应对各种需求,例如提供文字显示的TextView,提供点击事件的Button,提供图片显示的ImageView等等。还有各种能够填充上面这些具体View的父类容器,例如Relatwilayout,LinearLayout等等,他们都是继承自View。

    一种思考

    android中用每一个具体的子View去处理相对应的界面显示逻辑,而不是采用仅使用一个view进行处理。体现了一种编程思想:要尽可能的把事情少做,不要做大而全的东西,要做小而精的东西。同时每一个View只做自己份内的事情,而不过多的干涉其他事情,要显示文字就用TextView显示文字,要显示图片就用ImageView显示图片体现了面向对象和封装的思想。

    ViewGroup

    它是一个抽象类,继承自View,并实现了两个接口。其作用是承装子View,确定子View在其内部的位置。ViewGroup中含有一个抽象方法,这个方法就是用来确定子View的位置,是每一个子类必须继承的,而每一个子类对其进行不同程度的重载实现。实现的两个接口之一是ViewManager,它提供了三个抽象方法:addView(),removeView(),updateViewLayout(),用来添加、删除、更新布局。另一个接口则是ViewParent,主要提供了一系列操作子View的方法,例如焦点的切换,显示区域的控制等等。

    ViewParent

    通常获取一个View的父View调用的是getparent()方法,这个方法获取到的不是一个View对象,而是一个ViewParent对象。 看源码可知其中的方法都是用来管理子View的,例如:

    • requestLayout() 请求重新布局
    • invalidateChild() 绘制子View
    • cleanChildFouros() 清除子View的焦点
    • forcusSearch() 寻找下一个能获取焦点的子View
    • hringChildToFront() 把子View放置到前台

      ViewManager

      其中的addView()方法只是把View添加到其内部的View数组当中,我们可以看一下源码:

      /**
       * Adds a child view. If no layout parameters are already set on the child, the
       * default parameters for this ViewGroup are set on the child.
       * 
       * <p><strong>Note:</strong> do not invoke this method from
       * {@link #draw(android.graphics.Canvas)}, {@link #onDraw(android.graphics.Canvas)},
       * {@link #dispatchDraw(android.graphics.Canvas)} or any related method.</p>
       *
       * @param child the child view to add
       * @param index the position at which to add the child
       *
       * @see #generateDefaultLayoutParams()
       */
      public void addView(View child, int index) {
          if (child == null) {
              throw new IllegalArgumentException("Cannot add a null child view to a ViewGroup");
          }
          LayoutParams params = child.getLayoutParams();
          if (params == null) {
              params = generateDefaultLayoutParams();
              if (params == null) {
                  throw new IllegalArgumentException("generateDefaultLayoutParams() cannot return null");
              }
          }
          addView(child, index, params);
      }
      

      这里很简单,没有什么可说的,我们发现addView()方法最终还会调用自己的重载方法,而重载方法最终还会调用addViewInner()方法,在这个方法中我们会看到:

      private void addViewInner(View child, int index, LayoutParams params,
              boolean preventRequestLayout) {
      
          if (mTransition != null) {
              // Don't prevent other add transitions from completing, but cancel remove
              // transitions to let them complete the process before we add to the container
              mTransition.cancel(LayoutTransition.DISAPPEARING);
          }
      
          if (child.getParent() != null) {
              throw new IllegalStateException("The specified child already has a parent. " +
                      "You must call removeView() on the child's parent first.");
          }
      
          ......
      }
      

      上述代码也就是说,如果一个被添加进来的View已经有一个父View,就会抛异常。也就是说:
      1.一个View有且只有一个父View; 2.父View和子View之间是一对多的关系,即使父View是同一个也不行。

results matching ""

    No results matching ""