自定义ViewGroup,你真正懂了吗?

LoreneXJE 8年前
   <h3><strong>背景</strong></h3>    <p>自定义View简单,因为它只需管好自己即可,而自定义ViewGroup不仅仅要管好自己,还要管好子View。接触过ViewGroup的童鞋应该都清楚,ViewGroup是作为一个View的容器,它装着子View并将子View放到指定位置上去。</p>    <h3><strong>目的</strong></h3>    <p>让大家举一反三地去自定义定制化的GroupView</p>    <h3>思路</h3>    <p>自定义GroupView思路</p>    <ul>     <li> <p>首先需要知道子View大小,然后才能确定自定义的GroupView如何设置才能容纳它们。</p> </li>     <li> <p>根据子View的大小和ViewGroup需要实现的效果,确定最终ViewGroup的大小。</p> </li>     <li> <p>ViewGroup和子View的大小确定后,接着就是如何去摆放子View,你可以按照自己特定的规则去摆放。</p> </li>     <li> <p>然后将子View对号入座放入已知的分割单元。</p> </li>    </ul>    <h3><strong>实践</strong></h3>    <p>接下来我做一个示例将子View按从左到右顺序一个挨着一个摆放,即模仿实现LinearLayout的横向布局。</p>    <p>首先重写onMeasure,测量子View大小以及设定ViewGroup最终大小,代码如下:</p>    <pre>  <code class="language-java">@Override      protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {          super.onMeasure(widthMeasureSpec, heightMeasureSpec);          // 对所有子view进行测量,触发所有子view的onMeasure函数          measureChildren(widthMeasureSpec, heightMeasureSpec);            // 宽度模式          int widthMode = MeasureSpec.getMode(widthMeasureSpec);          // 测量宽度          int widthSize = MeasureSpec.getSize(widthMeasureSpec);          // 高度模式          int heightMode = MeasureSpec.getMode(heightMeasureSpec);          // 测量高度          int heightSize = MeasureSpec.getSize(heightMeasureSpec);          // 子view数目          int childCount = getChildCount();          if (childCount == 0){              // 如果当前ViewGroup没有子View,就没有存在的意义,无需占空间              setMeasuredDimension(0, 0);          }else {              // 如果宽高都是包裹内容              if (widthMode == MeasureSpec.AT_MOST && heightMode == MeasureSpec.AT_MOST){                  // 宽度为所有子view宽度相加,高度取子view最大高度                  int width = getTotalWidth();                  int height = getMaxHeight();                  setMeasuredDimension(width, height);              }else if (widthMode == MeasureSpec.AT_MOST){                  // 宽度为所有子View宽度相加,高度为测量高度                  setMeasuredDimension(getTotalWidth(), heightSize);              }else if (heightMode == MeasureSpec.AT_MOST){                  // 宽度为测量宽度,高度为子view最大高度                  setMeasuredDimension(widthSize, getMaxHeight());              }          }      }          /**       * 获取子view最大高度       * @author leibing       * @createTime 2016/09/19       * @lastModify 2016/09/19       * @param       * @return       */      private int getMaxHeight() {          // 最大高度          int maxHeight = 0;          // 子view数目          int childCount = getChildCount();          // 遍历子view拿取最大高度          for (int i=0;i<childCount;i++){              View childView = getChildAt(i);              if (childView.getMeasuredHeight() > maxHeight)                  maxHeight = childView.getMeasuredHeight();          }            return maxHeight;      }        /**       * 所有子view宽度相加       * @author leibing       * @createTime 2016/09/19       * @lastModify 2016/09/19       * @param       * @return       */      private int getTotalWidth() {          // 所有子view宽度之和          int totalWidth = 0;          // 子View数目          int childCount  = getChildCount();          // 遍历所有子view拿取所有子view宽度之和          for (int i=0;i<childCount;i++){              View childView = getChildAt(i);              totalWidth += childView.getMeasuredWidth();          }          return totalWidth;      }</code></pre>    <p>接下来将子View摆放到合适的位置上去,代码如下:</p>    <pre>  <code class="language-java">@Override      protected void onLayout(boolean changed, int l, int t, int r, int b) {          // 子view数目          int childCount = getChildCount();          // 记录当前宽度位置          int currentWidth = l;          // 逐个摆放子view          for (int i = 0;i<childCount;i++){              View childView = getChildAt(i);              int height = childView.getMeasuredHeight();              int width = childView.getMeasuredWidth();              // 摆放子view,参数分别是子view矩形区域的左、上,右,下。              childView.layout(currentWidth, t, currentWidth + width, t + height);              currentWidth += width;          }      }</code></pre>    <p>运行效果图如下所示:</p>    <p><img src="https://simg.open-open.com/show/61a9605e6d8da1ca79f79c1e49216884.gif"></p>    <p style="text-align:center">CustomViewGroup.gif</p>    <p>童鞋们,看完后,自定义ViewGroup是不是很简单了?</p>    <p> </p>    <p>来自:http://www.jianshu.com/p/07ac5921fed8</p>    <p> </p>