自定义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>