是否可以使用RelativeLayout属性实现FlowLayout?

时间:2016-01-21 03:53:25

标签: android android-layout

我想创建一个自定义RelativeLayout,它在一行中有两个视图:一个在屏幕的左侧(android:layout_alignParentStart =" true"),另一个在右边(android:layout_alignParentEnd) ="真&#34)。右侧的视图将朝向左视图增长,直到占据两个视图之间的所有空间。然后它将移动到左侧视图下的新行。

我已经实现了一个稍微修改过的Romain Guy的FlowLayout版本,它扩展了RelativeLayout。但是,这个类似乎忽略了RelativeLayout的对齐属性,只是将视图紧挨着彼此。有没有办法实现这样的布局,将视图锚定到左侧和右侧?

FlowLayout类:

public class FlowLayout extends RelativeLayout {

private int mHorizontalSpacing;
private int mVerticalSpacing;

public FlowLayout(Context context) {
    super(context);
}

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

    TypedArray attributes = context.obtainStyledAttributes(attrs, R.styleable.FlowLayout);
    mHorizontalSpacing = attributes.getDimensionPixelSize(R.styleable
            .FlowLayout_horizontalSpacing, 0);
    mVerticalSpacing = attributes.getDimensionPixelSize(R.styleable
            .FlowLayout_verticalSpacing, 0);
    attributes.recycle();
}

@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
    int widthSize = MeasureSpec.getSize(widthMeasureSpec);

    int width = 0;
    int height = getPaddingTop();

    int currentWidth = getPaddingStart();
    int currentHeight = 0;

    final int count = getChildCount();
    for (int i = 0; i < count; i++) {
        View child = getChildAt(i);
        LayoutParams lp = (LayoutParams) child.getLayoutParams();
        measureChild(child, widthMeasureSpec, heightMeasureSpec);

        if (currentWidth + child.getMeasuredWidth() > widthSize) {
            height += currentHeight + mVerticalSpacing;
            currentHeight = 0;
            width = Math.max(width, currentWidth);
            currentWidth = getPaddingEnd();
        }

        int spacing = mHorizontalSpacing;
        if (lp.spacing > -1) {
            spacing = lp.spacing;
        }

        lp.x = currentWidth + spacing;
        lp.y = currentHeight;

        currentWidth += child.getMeasuredWidth();
        currentHeight = Math.max(currentHeight, child.getMeasuredHeight());
    }

    width += getPaddingEnd();
    height += getPaddingBottom();

    setMeasuredDimension(resolveSize(width, widthMeasureSpec), resolveSize(height,
            heightMeasureSpec));

}

@Override
protected void onLayout(boolean changed, int l, int t, int r, int b) {
    final int count = getChildCount();
    for (int i = 0; i < count; i++) {
        View child = getChildAt(i);
        LayoutParams lp = (LayoutParams) child.getLayoutParams();
        child.layout(lp.x, lp.y, lp.x + child.getMeasuredWidth(), lp.y + child
                .getMeasuredHeight());
    }
}

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

@Override
protected ViewGroup.LayoutParams generateDefaultLayoutParams() {
    return new LayoutParams(RelativeLayout.LayoutParams.WRAP_CONTENT, RelativeLayout
            .LayoutParams.WRAP_CONTENT);
}

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

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

public static class LayoutParams extends RelativeLayout.LayoutParams {

    public int spacing;

    public int x;
    public int y;

    public LayoutParams(Context context, AttributeSet attrs) {
        super(context, attrs);

        TypedArray attributes = context.obtainStyledAttributes(attrs, R.styleable
                .FlowLayout_LayoutParams);
        spacing = attributes.getDimensionPixelSize(R.styleable
                .FlowLayout_LayoutParams_layoutSpacing, -1);
        attributes.recycle();
    }

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

}

1 个答案:

答案 0 :(得分:0)

事实证明,您可以更改其LayoutParams并让操作系统为您处理定位,而不是自己计算正确视图的新位置。我创建了一个自定义布局,扩展了RelativeLayout并覆盖了onMeasure()方法。这将相应地调整LayoutParams。

更具体地说: 调用super方法然后在onMeasure()中找到两个视图及其父级的宽度。使用这些来确定右视图是否与左视图重叠。如果是,请将正确视图的layout_alignParentEnd="true"属性更改为layout_alignParentStart="true",并为其提供layout_below="@id/left_view"属性。当没有重叠时,反之亦然。再次调用super方法让操作系统为您重新测量视图。

布局类:

public class WrappingLayout extends RelativeLayout {

    private TextView leftView;
    private EditText rightView;
    //Use this to prevent unnecessarily adjusting the LayoutParams
    //when the right view is already in the correct position
    private boolean isMultiline = false;

    public WrappingLayout(Context context) {
        super(context);
        LayoutInflater inflater = LayoutInflater.from(context);
        inflater.inflate(R.layout.wrapping_layout, this);

        leftView = (TextView) findViewById(R.id.left_view);
        rightView = (EditText) findViewById(R.id.right_view);
    }

    public WrappingLayout(Context context, AttributeSet attrs) {
        super(context, attrs);
        LayoutInflater inflater = LayoutInflater.from(context);
        inflater.inflate(R.layout.wrapping_layout, this);

        leftView = (TextView) findViewById(R.id.left_view);
        rightView = (EditText) findViewById(R.id.right_view);
    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        //Call first to make sure the views' initial widths have been set
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
        int screenWidth = getMeasuredWidth();
        int leftViewWidth = getPaddingStart() + leftView.getMeasuredWidth() + leftView.getPaddingEnd();
        int rightViewWidth = getPaddingEnd() + rightView.getMeasuredWidth() + rightView.getPaddingStart();

        LayoutParams rightViewParams = (LayoutParams) rightView.getLayoutParams();
        if (!isMultiline && rightViewWidth + leftViewWidth > screenWidth) {
            isMultiline = true;
            rightViewParams.addRule(BELOW, R.id.left_view);
            rightViewParams.removeRule(ALIGN_PARENT_END);
            rightViewParams.addRule(ALIGN_PARENT_START);
            //Call again here to adjust dimensions for new params
            super.onMeasure(widthMeasureSpec, heightMeasureSpec);
        } else if (isMultiline && rightViewWidth + leftViewWidth < screenWidth) {
            isMultiline = false;
            rightViewParams.removeRule(BELOW);
            rightViewParams.addRule(ALIGN_PARENT_END);
            rightViewParams.removeRule(ALIGN_PARENT_START);
            //Call again here to adjust dimensions for new params
            super.onMeasure(widthMeasureSpec, heightMeasureSpec);
        }
    }

}

布局XML:

<?xml version="1.0" encoding="utf-8"?>
<merge
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <TextView
        android:id="@id/left_view"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignParentStart="true"
        android:layout_centerVertical="true"/>

    <EditText
        android:id="@id/right_view"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignParentEnd="true"
        android:gravity="center"
        android:text="@string/hello"/>

</merge>