2

我想要以下布局

|     AA  BBBBBBB |

除非没有足够的空间,在这种情况下我想要

|       AA |
|  BBBBBBB |

在这种情况下A是复选框,并且B是复选框旁边的 TextView。

你能推荐一个支持这样包装的布局吗?

4

2 回答 2

1

换行布局...

支持视图的“自动换行”的布局中?,在 Android Developers Google 小组中,他们正是在问这个问题。两个人编写了自己的布局,所以也许它可以帮助你。

于 2012-07-11T23:07:39.570 回答
0

没有官方的 Android ViewGroup 可以做到这一点,但您可以创建具有这种行为的子类。

package your.package.here;

import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import android.content.Context;
import android.content.res.TypedArray;
import android.util.AttributeSet;
import android.view.View;
import android.view.ViewGroup;

public class FlowLayout extends ViewGroup {
    private int[] rowHeights;

    public FlowLayout(Context context, AttributeSet attrs) {
        super(context, attrs);
    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        int widthMode = MeasureSpec.getMode(widthMeasureSpec);
        int heightMode = MeasureSpec.getMode(heightMeasureSpec);
        int maxInternalWidth = MeasureSpec.getSize(widthMeasureSpec) - getHorizontalPadding();
        int maxInternalHeight = MeasureSpec.getSize(heightMeasureSpec) - getVerticalPadding();
        List<RowMeasurement> rows = new ArrayList<RowMeasurement>();
        RowMeasurement currentRow = null;
        for (View child : getLayoutChildren()) {
            LayoutParams childLayoutParams = (LayoutParams)child.getLayoutParams();
            int childWidthSpec = createChildMeasureSpec(childLayoutParams.width, maxInternalWidth, widthMode);
            int childHeightSpec = createChildMeasureSpec(childLayoutParams.height, maxInternalHeight, heightMode);
            child.measure(childWidthSpec, childHeightSpec);
            int childWidth = child.getMeasuredWidth();
            int childHeight = child.getMeasuredHeight();
            if ((currentRow == null) || currentRow.isWouldExceedMax(childWidth))
            {
                currentRow = new RowMeasurement(maxInternalWidth, widthMode);
                rows.add(currentRow);
            }
            currentRow.addChildDimensions(childWidth, childHeight);
        }
        int longestRowWidth = 0;
        int totalRowHeight = 0;
        int rowCount = rows.size();
        this.rowHeights = new int[rowCount];
        for (int rowIndex = 0; rowIndex < rowCount; rowIndex++) {
            RowMeasurement row = rows.get(rowIndex);
            int rowHeight = row.getHeight();
            this.rowHeights[rowIndex] = rowHeight;
            totalRowHeight = totalRowHeight + rowHeight;
            longestRowWidth = Math.max(longestRowWidth, row.getWidth());
        }
        setMeasuredDimension(
            (widthMode == MeasureSpec.EXACTLY) ? 
                MeasureSpec.getSize(widthMeasureSpec) : 
                (longestRowWidth + getHorizontalPadding()), 
            (heightMode == MeasureSpec.EXACTLY) ? 
                MeasureSpec.getSize(heightMeasureSpec) : 
                (totalRowHeight + getVerticalPadding())
        );
    }

    private int createChildMeasureSpec(int childLayoutParam, int max, int parentMode) {
        int spec;
        if (childLayoutParam == ViewGroup.LayoutParams.FILL_PARENT)
            spec = MeasureSpec.makeMeasureSpec(max, MeasureSpec.EXACTLY);
        else if (childLayoutParam == ViewGroup.LayoutParams.WRAP_CONTENT)
            spec = MeasureSpec.makeMeasureSpec(max, ((parentMode == MeasureSpec.UNSPECIFIED) ? 
                MeasureSpec.UNSPECIFIED : MeasureSpec.AT_MOST)
            );
        else
            spec = MeasureSpec.makeMeasureSpec(childLayoutParam, MeasureSpec.EXACTLY);
        return spec;
    }

    @Override
    protected LayoutParams generateDefaultLayoutParams() {
        return new LayoutParams();
    }

    @Override
    protected boolean checkLayoutParams(ViewGroup.LayoutParams layoutParams) {
        return (layoutParams instanceof LayoutParams);
    }

    @Override
    public LayoutParams generateLayoutParams(AttributeSet attrs) {
        return new LayoutParams(getContext(), attrs);
    }

    @Override
    protected ViewGroup.LayoutParams generateLayoutParams(ViewGroup.LayoutParams p){
        return new LayoutParams(p);
    }

    @Override
    protected void onLayout(boolean changed, int leftPosition, int topPosition, int rightPosition, int bottomPosition) {
        int widthOffset = getMeasuredWidth() - getPaddingRight();
        int x = getPaddingLeft();
        int y = getPaddingTop();
        int rowIndex = 0;
        for (View child : getLayoutChildren()) {
            int childWidth = child.getMeasuredWidth();
            int childHeight = child.getMeasuredHeight();
            LayoutParams layoutParams = (LayoutParams)child.getLayoutParams();
            if ((x + childWidth) > widthOffset) {
                x = getPaddingLeft();
                y = y + this.rowHeights[rowIndex];
                rowIndex = rowIndex + 1;
            }
            int _y;
            if (layoutParams.centerVertical)
                _y = y + ((this.rowHeights[rowIndex] - childHeight) / 2);
            else
                _y = y;
            child.layout(x, _y, x + childWidth, _y + childHeight);
            x = x + childWidth;
        }
    }

    private Collection<View> getLayoutChildren() {
        int count = getChildCount();
        Collection<View> children = new ArrayList<View>(count);
        for (int index = 0; index < count; index++)
        {
            View child = getChildAt(index);
            if (child.getVisibility() != View.GONE)
                children.add(child);
        }
        return children;
    }

    private int getVerticalPadding() {
        return getPaddingTop() + getPaddingBottom();
    }

    private int getHorizontalPadding() {
        return getPaddingLeft() + getPaddingRight();
    }

    public static class LayoutParams extends MarginLayoutParams {
        boolean centerVertical;

        public LayoutParams() {
            this(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT);
        }

        public LayoutParams(int width, int height) {
            super(width, height);
            setCenterVertical(false);
        }

        public LayoutParams(Context context, AttributeSet attrs) {
            super(context, attrs);
            TypedArray attributes = context.obtainStyledAttributes(attrs, new int[] { android.R.attr.layout_centerVertical });
            setCenterVertical(attributes.getBoolean(0, false));
            attributes.recycle();
        }

        public LayoutParams(ViewGroup.LayoutParams source) {
            super(source);
        }

        public LayoutParams(MarginLayoutParams source) {
            super(source);
        }

        public LayoutParams(LayoutParams source) {
            this(source.width, source.height);
        }

        public void setCenterVertical(boolean centerVertical) {
            this.centerVertical = centerVertical;
        }
    }

    private static class RowMeasurement {
        private int maxWidth;
        private int widthMode;
        private int width;
        private int height;

        RowMeasurement(int maxWidth, int widthMode) {
            this.maxWidth = maxWidth;
            this.widthMode = widthMode;
        }

        int getWidth() {
            return this.width;
        }

        int getHeight() {
            return this.height;
        }

        boolean isWouldExceedMax(int childWidth) {
            return ((this.widthMode != MeasureSpec.UNSPECIFIED) && (getNewWidth(childWidth) > this.maxWidth));
        }

        void addChildDimensions(int childWidth, int childHeight) {
            this.width = getNewWidth(childWidth);
            this.height = Math.max(this.height, childHeight);
        }

        private int getNewWidth(int childWidth) {
            return ((this.width == 0) ? childWidth : (this.width + childWidth));
        }
    }
}

然后在布局中使用它:

<your.package.here.FlowLayout
android:layout_width="match_parent"
android:layout_height="wrap_content">
    <TextView ... />
    <ImageView ... />
    <TextView ... />
</your.package.here.FlowLayout>

此解决方案感谢 Zsolt Vasvari,感谢 David Cesarino 发布链接。

于 2014-01-16T16:12:11.177 回答