美文网首页编程view
Android自定义View实践之ViewGroup

Android自定义View实践之ViewGroup

作者: _罪 | 来源:发表于2019-11-15 11:30 被阅读0次

    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",即可

    <com.summer.myapplication.widget.NoneCompressLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        app:layout_constraintTop_toTopOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintEnd_toEndOf="parent">
    
        <EditText
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:maxLines="1"
            android:singleLine="true"
            android:ellipsize="end" />
    
        <TextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="固定内容"
            app:complete="true"
            android:layout_marginEnd="10dp"
            android:layout_marginStart="16dp" />
    
    </com.summer.myapplication.widget.NoneCompressLayout>
    

    详细代码

    相关文章

      网友评论

        本文标题:Android自定义View实践之ViewGroup

        本文链接:https://www.haomeiwen.com/subject/vdijictx.html