美文网首页
文字后面紧跟标签SpareLayout

文字后面紧跟标签SpareLayout

作者: 常强儿 | 来源:发表于2017-11-14 20:36 被阅读43次

来一波需求

有这样一种需求,前面一个View,后面要带着几个标签,如果前面的View不太大,那么标签紧跟标签向前移动(后三个条目),如果前面的View就很大,余下来足够的空间放标签(第一个条目)


�酷我音乐的标签.png

有一个想法

自己定义一个ViewGroup,类似于水平布局的LinearLayout,优先测量后面的View,最后将剩余的空间给第一个View,在layout的时候从左向右摆放,最终实现效果,给新的ViewGroup起名叫SpareLayout

  • 测量的时候从最后一个子View开始测量
  • 累加后面所有View的宽度,将剩余空间给第一个View
  • 高度使用最大高度的View
  • layout时从左向右摆放测量好的View

做一点实现

按上面的思路重写onMeasure和onLayout方法

@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
    int widthSize = MeasureSpec.getSize(widthMeasureSpec);
    //余下的空间
    int spareWidth = 0;
    //最大高度
    int maxHeight = 0;
    //子view从后向前测量
    for (int i = getChildCount() - 1; i > 0; i--) {
        View child = getChildAt(i);
        //不可见的跳过
        if (child.getVisibility() == GONE) {
            continue;
        }
        //测量一个子View,并处理padding,margin
        measureChild(child, widthMeasureSpec, heightMeasureSpec);
        FrameLayout.LayoutParams lp = (LayoutParams) child.getLayoutParams();
        int marginWidth = lp.leftMargin + lp.rightMargin;
        int marginHeight = lp.topMargin + lp.bottomMargin;
        spareWidth += child.getMeasuredWidth() + marginWidth;
        maxHeight = Math.max(maxHeight, child.getMeasuredHeight() + marginHeight);
    }
    //最后来测量第一个View,使用的方式是AT_MOST,宽度是剩余空间
    View firstChild = getChildAt(0);
    FrameLayout.LayoutParams lp = (LayoutParams) firstChild.getLayoutParams();
    int marginWidth = lp.leftMargin + lp.rightMargin;
    int marginHeight = lp.topMargin + lp.bottomMargin;
    int paddingWidth = getPaddingLeft() + getPaddingRight();
    int paddingHeight = getPaddingTop() + getPaddingBottom();
    int firstViewWidthSpec =
         MeasureSpec.makeMeasureSpec(widthSize - spareWidth - marginWidth - paddingWidth,
            MeasureSpec.AT_MOST);
    measureChild(firstChild, firstViewWidthSpec, heightMeasureSpec);
    maxHeight = Math.max(firstChild.getMeasuredHeight() + marginHeight, maxHeight);
    //储存测量结果
    setMeasuredDimension(spareWidth + firstChild.getMeasuredWidth() + paddingWidth,
        maxHeight + paddingHeight);
}

测量得到了每一个View应该的大小,接下来就是摆放所有的子View,看过来onLayout()

@Override
protected void onLayout(boolean changed, int l, int t, int r, int b) {
    int left = 0;
    //从左向右排放View
    for (int i = 0; i < getChildCount(); i++) {
        View child = getChildAt(i);
        if (child.getVisibility() == GONE) {
            continue;
        }
        FrameLayout.LayoutParams lp = (LayoutParams) child.getLayoutParams();
        int leftStart = left + lp.leftMargin + getPaddingLeft();
        int topStart;

        //处理vertical的gravity
        final int verticalGravity = lp.gravity & Gravity.VERTICAL_GRAVITY_MASK;
        switch (verticalGravity) {
            case Gravity.TOP:
                //从上向下计算
                topStart = lp.topMargin + getPaddingTop();
                break;
            case Gravity.CENTER_VERTICAL:
                //vertical的居中,是指view居中(除去这个SpareLayout的padding和子View的margin居中)
                topStart = (t + getPaddingTop() + lp.topMargin +    //可以放view的空间上边
                    b - getPaddingBottom() - lp.bottomMargin        //可以放view的空间下边
                    - child.getMeasuredHeight()) / 2                //中心线
                    - t;                                            //计算出view的上边
                break;
            case Gravity.BOTTOM:
                //从下向上算的
                topStart =
                    b - lp.bottomMargin - getPaddingBottom() - child.getMeasuredHeight() - t;
                break;
            default:
                //默认是在上面
                topStart = lp.topMargin + getPaddingTop();
        }
        child.layout(leftStart, topStart, leftStart + child.getMeasuredWidth(),
            topStart + child.getMeasuredHeight());
        //累加左边已经使用的空间
        left += child.getMeasuredWidth() + lp.leftMargin + lp.rightMargin;
    }
}

这样实现的效果:


�文本比较长的时候.png
�文本比较短的情况.png

提一些Tips

如果后面几个标签已经很大的情况没有处理
以前为这个效果试验了各种方式,跑包的时间都比停下来写这个控件时间长得多,以后注意不要再做这样的事
使用linearLayout的weight属性并没有成功

相关文章

  • 文字后面紧跟标签SpareLayout

    来一波需求 有这样一种需求,前面一个View,后面要带着几个标签,如果前面的View不太大,那么标签紧跟标签向前移...

  • 标签模板及其应用

    1、标签模板 标签模板其实不是模板,而是函数调用的一种特殊形式。“标签”指的就是数,紧跟在后面的模板字符串就是它的...

  • storyboard xib下label怎么自适应宽度高度

    先看需求:两个Label,要求蓝色的label紧跟在红色的label文字后面 红色label上文字短时,正常显示,...

  • es6:模板字符串

    模板字符串:${变量名}标签模板:是函数调用的一种特殊形式,标签指的是函数紧跟在后面的模板字符串就是它的参数 st...

  • H5-day1-基础标签

    标签 1.html中是不识别空格,tab和回车的。其中: 空格 这是段落 换行 如果回车后面紧跟br会被识别成一个...

  • 自定义 input type="file"

    原生的 标签在Firefox下显示是这样的: 其中的选择文件的按钮和后面文字是一体的,点击后面的文字同样可以进行文...

  • iOS在xib下约束前后两个控件的宽度

    需求:两个Label,要求蓝色的label紧跟在红色的label文字后面。### 先创建两个空的 view 1、首...

  • css选择器

    元素关系选择器 名称举例意义子选择器div>pdiv 的子标签p相邻兄弟选择器img+p图片后面紧跟着的段落将被选...

  • FCC问题集锦

    1. a标签结束标签斜杠后加空格导致图片和后面的文字都被当成了链接内容,去掉空格则一切正常。

  • HTML笔记-文字标签和注释标签

    HTML笔记-文字标签和注释标签 标签(空格分隔): HTML HTML中常用的标签 文字标签: 修改文字的样式 ...

网友评论

      本文标题:文字后面紧跟标签SpareLayout

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