断行小部件的布局为Android部件、布局、Android

2023-09-11 11:11:10 作者:喧嚣

我试图创建presents一些数据给用户的活动。数据是这样的,它可以分成'单词',每个都是插件,和序列的'单词'将构成数据('句子'?),含有该字的ViewGroup插件。根据需要空间来容纳所有的话'在'一句话'将超过上显示的可用水平空间,我想换行这些'句子',你会正常的一段文字。

I'm trying to create an activity that presents some data to the user. The data is such that it can be divided into 'words', each being a widget, and sequence of 'words' would form the data ('sentence'?), the ViewGroup widget containing the words. As space required for all 'words' in a 'sentence' would exceed the available horizontal space on the display, I would like to wrap these 'sentences' as you would a normal piece of text.

下面code:

public class WrapTest extends Activity {
	/** Called when the activity is first created. */
	@Override
	public void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		LinearLayout l = new LinearLayout(this);
		LinearLayout.LayoutParams lp = new LinearLayout.LayoutParams(
				LinearLayout.LayoutParams.FILL_PARENT,
				LinearLayout.LayoutParams.WRAP_CONTENT);
		LinearLayout.LayoutParams mlp = new LinearLayout.LayoutParams(
				new ViewGroup.MarginLayoutParams(
						LinearLayout.LayoutParams.WRAP_CONTENT,
						LinearLayout.LayoutParams.WRAP_CONTENT));
		mlp.setMargins(0, 0, 2, 0);

		for (int i = 0; i < 10; i++) {
			TextView t = new TextView(this);
			t.setText("Hello");
			t.setBackgroundColor(Color.RED);
			t.setSingleLine(true);
			l.addView(t, mlp);
		}

		setContentView(l, lp);
	}
}

产生类似左侧图片,但我想一个布局presenting相同的部件就像那个合适的人。

yields something like the left picture, but I would want a layout presenting the same widgets like in the right one.

有这样的布局布局和参数或组合,还是我要实现我自己的ViewGroup这个?

Is there such a layout or combination of layouts and parameters, or do I have to implement my own ViewGroup for this?

推荐答案

我做我自己的布局,做什么我想要的,但仍然是相当有限的时刻。意见和改进建议当然是受欢迎的。

I made my own layout that does what I want, but it is quite limited at the moment. Comments and improvement suggestions are of course welcome.

活动:

package se.fnord.xmms2.predicate;

import se.fnord.android.layout.PredicateLayout;
import android.app.Activity;
import android.graphics.Color;
import android.os.Bundle;
import android.widget.TextView;

public class Predicate extends Activity {
    /** Called when the activity is first created. */
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        PredicateLayout l = new PredicateLayout(this);
        for (int i = 0; i < 10; i++) {
            TextView t = new TextView(this);
            t.setText("Hello");
            t.setBackgroundColor(Color.RED);
            t.setSingleLine(true);
            l.addView(t, new PredicateLayout.LayoutParams(2, 0));
        }

        setContentView(l);
    }
}

或XML布局:

Or in an XML layout:

<se.fnord.android.layout.PredicateLayout
    android:id="@+id/predicate_layout"
    android:layout_width="fill_parent" 
    android:layout_height="wrap_content"
/>

和布局:

package se.fnord.android.layout;

import android.content.Context;
import android.util.AttributeSet;
import android.view.View;
import android.view.ViewGroup;

/**
 * ViewGroup that arranges child views in a similar way to text, with them laid
 * out one line at a time and "wrapping" to the next line as needed.
 * 
 * Code licensed under CC-by-SA
 *  
 * @author Henrik Gustafsson
 * @see http://stackoverflow.com/questions/549451/line-breaking-widget-layout-for-android
 * @license http://creativecommons.org/licenses/by-sa/2.5/
 *
 */
public class PredicateLayout extends ViewGroup {

    private int line_height;

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

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

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        assert(MeasureSpec.getMode(widthMeasureSpec) != MeasureSpec.UNSPECIFIED);

        final int width = MeasureSpec.getSize(widthMeasureSpec);

        // The next line is WRONG!!! Doesn't take into account requested MeasureSpec mode!
        int height = MeasureSpec.getSize(heightMeasureSpec) - getPaddingTop() - getPaddingBottom();
        final int count = getChildCount();
        int line_height = 0;

        int xpos = getPaddingLeft();
        int ypos = getPaddingTop();

        for (int i = 0; i < count; i++) {
            final View child = getChildAt(i);
            if (child.getVisibility() != GONE) {
                final LayoutParams lp = (LayoutParams) child.getLayoutParams();
                child.measure(
                        MeasureSpec.makeMeasureSpec(width, MeasureSpec.AT_MOST),
                        MeasureSpec.makeMeasureSpec(height, MeasureSpec.UNSPECIFIED));

                final int childw = child.getMeasuredWidth();
                line_height = Math.max(line_height, child.getMeasuredHeight() + lp.height);

                if (xpos + childw > width) {
                    xpos = getPaddingLeft();
                    ypos += line_height;
                }

                xpos += childw + lp.width;
            }
        }
        this.line_height = line_height;

        if (MeasureSpec.getMode(heightMeasureSpec) == MeasureSpec.UNSPECIFIED){
            height = ypos + line_height;

        } else if (MeasureSpec.getMode(heightMeasureSpec) == MeasureSpec.AT_MOST){
            if (ypos + line_height < height){
                height = ypos + line_height;
            }
        }
        setMeasuredDimension(width, height);
    }

    @Override
    protected LayoutParams generateDefaultLayoutParams() {
        return new LayoutParams(1, 1); // default of 1px spacing
    }

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

    @Override
    protected void onLayout(boolean changed, int l, int t, int r, int b) {
        final int count = getChildCount();
        final int width = r - l;
        int xpos = getPaddingLeft();
        int ypos = getPaddingTop();

        for (int i = 0; i < count; i++) {
            final View child = getChildAt(i);
            if (child.getVisibility() != GONE) {
                final int childw = child.getMeasuredWidth();
                final int childh = child.getMeasuredHeight();
                final LayoutParams lp = (LayoutParams) child.getLayoutParams();
                if (xpos + childw > width) {
                    xpos = getPaddingLeft();
                    ypos += line_height;
                }
                child.layout(xpos, ypos, xpos + childw, ypos + childh);
                xpos += childw + lp.width;
            }
        }
    }
}

通过结果: