Android自定义View实践之ViewGroup

Android 自定义ViewGroup实践—让某些子View优先显示完整(压缩其它View)

效果图

screen_shot.png

效果分析

  1. 子View横向排列
  2. 子View竖直居中
  3. 标记为显示完整的View能尽可能地完整显示

实现方式

测量--重写onMeasure(int widthMeasureSpec, int heightMeasureSpec)方法

  • 由于有优先完整显示的子View,所以第一次遍历所有子View找到需要优先显示的子View进行测量,直接调用ViewGoup中的measureChildWithMargins获取测量宽高,如下:
int widthUsed = 0;
for (int i = 0; i < getChildCount(); i++) {
    View child = getChildAt(i);
    LayoutParams params = (LayoutParams) child.getLayoutParams();
    widthUsed += params.leftMargin;
    widthUsed += params.rightMargin;
    //如果是固定宽度的布局
    if (params.complete) {
        measureChildWithMargins(child, widthMeasureSpec, widthUsed, heightMeasureSpec, 0);
        widthUsed += child.getMeasuredWidth();
    }
}
  • 再次遍历测量未优先显示的子View,以剩余宽高来作为最大宽高来测量,具体代码如下:
for (int i = 0; i < getChildCount(); i++) {
    View child = getChildAt(i);
    LayoutParams params = (LayoutParams) child.getLayoutParams();
    widthUsed += params.leftMargin;
    widthUsed += params.rightMargin;
    if (!params.complete) {
        measureChildWithMargins(child, widthMeasureSpec, widthUsed, heightMeasureSpec, 0);
    }
    width += widthUsed;
    width += child.getMeasuredWidth();
    height = Math.max(height, params.topMargin + params.bottomMargin + child.getMeasuredHeight());
}
  • 经过以上的子View测量,我们能够很容易得到该ViewGroup需要的宽高,即上述中的width和height,调用setMeasuredDimension()方法设置ViewGroup的宽高。
setMeasuredDimension(getDefaultSize(width, widthMeasureSpec), getDefaultSize(height, heightMeasureSpec));

布局,重写onLayout(boolean changed, int l, int t, int r, int b)方法

  • 没啥说的,唯一需要注意的是child.layout()传入的是相对与改父View的相对坐标,直接遍历所有子View,调用子View的onLayout(int left,int top,int right,int bottom)方法,为了让margin生效,需要加上margin,代码如下:
int left = 0;
final int layoutHeight = b - t;
for (int i = 0; i < getChildCount(); i++) {
    View child = getChildAt(i);
    //获取测量宽度
    final int width = child.getMeasuredWidth();
    Log.d(TAG, "onLayout: " + width);
    //获取测量高度
    final int height = child.getMeasuredHeght();
    //计算居中的上下偏移量
    final int offset = (layoutHeight - height) / 2;
    MarginLayoutParams params = (MarginLayoutParams) child.getLayoutParams();
    //子View的左侧位置为left+左边距
    left += params.leftMargin;
    child.layout(left, offset, left + width, height + offset);
    Log.d(TAG, "onLayout: [left:" + (l + left) + "  top:" + (t + yOffset) + "  right:" + (l + left + width) + " bottom:" + (b - yOffset));
    //下一个View的左侧位置
    left += width + params.rightMargin;
}

使用方式,在需要尽可能显示完整的View中添加app:complete = "ture",即可



    

    


详细代码

你可能感兴趣的:(Android自定义View实践之ViewGroup)