Android which layout to use to overflow objects to the next line
Asked Answered
U

2

12

I am uncertain of what type of layout to use for this certain scenario.

I basically want to have a horizontal linear layout that i can add views to. in this case buttons (displaying tags in an application) But each view will have a different width bases on the name of the tag it is displaying, so i want to add say 10 tags, I need a layout that will fit as many as it can on the 1st line, and then if it doesn't fit, automatically overflow to the next line.

Basically how a text view works with text, if the text is longer than the width it goes to the next line, except I want to do this with non-clickable buttons.

I thought of a grid layout, but then it would have the same no of "tags" on each line when you could have 2 tags with a long name on the first line and 7 with a short name on the second line.

Something that looks a bit like this: enter image description here

I basically want the look of how stack overflow does it below here.

Underlay answered 13/9, 2013 at 6:57 Comment(6)
You can use singleline properties of textview.Intermediary
@Intermediary Care to elaborate more on that ?Underlay
@Underlay use horizontal ScrollviewLiddie
@Liddie will that not just scroll horizontally? I dont want it to scroll. It must just be put on the line below if it does not fit.Underlay
@Underlay why don't you use vertical linearlayout?Liddie
@Liddie vertical linearlayout willnot overflow to the next line. If there are more objects than what can fit on the line it will just bunch them up all on top of each other. I need a vertical linearlayout that if the objects are greater than its available width it puts the remaining on the next line?Underlay
G
5

Answer: Your own custom Layout :)

I know this is a late answer to this question. But it might help the OP or someone for sure.

You can extend ViewGroup to create a custom layout like this one below. The advantage of this is you get the keep the view hierarchy flat.

Android Studio is super smart to render a custom layout like any other layout!

MyFlowLayout

public class MyFlowLayout extends ViewGroup {

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

    public MyFlowLayout(Context context, AttributeSet attrs) {
        this(context,attrs,0);
    }

    public MyFlowLayout(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
    }

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

        int currentHeight = 0;
        int currentWidth = 0;

        int currentChildHookPointx = 0;
        int currentChildHookPointy = 0;

        int childCount = this.getChildCount();

        for(int i = 0; i < childCount; i++) {
            View child = getChildAt(i);
            this.measureChild(child, widthMeasureSpec, heightMeasureSpec);
            int childWidth = child.getMeasuredWidth();
            int childHeight = child.getMeasuredHeight();

            //check if child can be placed in the current row, else go to next line
            if(currentChildHookPointx + childWidth > realWidth) {
                //new line
                currentWidth = Math.max(currentWidth, currentChildHookPointx);

                //reset for new line
                currentChildHookPointx = 0;

                currentChildHookPointy += childHeight;
            }

            int nextChildHookPointx;
            int nextChildHookPointy;

            nextChildHookPointx = currentChildHookPointx + childWidth;
            nextChildHookPointy = currentChildHookPointy;

            currentHeight = Math.max(currentHeight, currentChildHookPointy + childHeight);

            LayoutParams lp = (LayoutParams) child.getLayoutParams();
            lp.x = currentChildHookPointx;
            lp.y = currentChildHookPointy;

            currentChildHookPointx = nextChildHookPointx;
            currentChildHookPointy = nextChildHookPointy;
        }

        currentWidth = Math.max(currentChildHookPointx, currentWidth);

        setMeasuredDimension(resolveSize(currentWidth, widthMeasureSpec),
                resolveSize(currentHeight, heightMeasureSpec));
    }

    @Override
    protected void onLayout(boolean b, int left, int top, int right, int bottom) {
        //call layout on children
        int childCount = this.getChildCount();
        for(int i = 0; i < childCount; i++) {
            View child = this.getChildAt(i);
            LayoutParams lp = (LayoutParams) child.getLayoutParams();
            child.layout(lp.x, lp.y, lp.x + child.getMeasuredWidth(), lp.y + child.getMeasuredHeight());
        }

    }

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

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

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

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

    public static class LayoutParams extends ViewGroup.MarginLayoutParams {

        int spacing = -1;
        int x = 0;
        int y = 0;

        LayoutParams(Context c, AttributeSet attrs) {
            super(c, attrs);
            TypedArray t = c.obtainStyledAttributes(attrs, R.styleable.FlowLayout_Layout);
            spacing = t.getDimensionPixelSize(R.styleable.FlowLayout_Layout_layout_space, 0);
            t.recycle();
        }

        LayoutParams(int width, int height) {
            super(width, height);
            spacing = 0;
        }

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

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

Usage in a layout.xml file

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    xmlns:cl="http://schemas.android.com/apk/res-auto"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    android:paddingBottom="@dimen/activity_vertical_margin"
    android:paddingLeft="@dimen/activity_horizontal_margin"
    android:paddingRight="@dimen/activity_horizontal_margin"
    android:paddingTop="@dimen/activity_vertical_margin"
    tools:context="com.merryapps.customlayout.MainActivity">

    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Hello World!" />

    <com.merryapps.customlayout.MyFlowLayout
        android:id="@+id/flw1"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:background="#FF0000">
        <Button
            android:id="@+id/b1"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="@string/hello"
            cl:layout_space="20dp"/>
        <Button
            android:id="@+id/b2"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="@string/world"/>

        <Button
            android:id="@+id/b4"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="@string/world"/>

        <Button
            android:id="@+id/b5"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="@string/world"/>

        <Button
            android:id="@+id/b6"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="@string/world"/>
    </com.merryapps.customlayout.MyFlowLayout>

    <Button
        android:id="@+id/b3"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="@string/world"
        android:textAllCaps="false"/>
</LinearLayout>
Guay answered 17/12, 2016 at 5:19 Comment(0)
C
2

For show type of view one must go for flow layout :- There are many libraries available on Git Following is the example of, blazsolar/FlowLayout

Add this line in app.gradle

compile "com.wefika:flowlayout:<version>"

Usage:-

<com.wefika.flowlayout.FlowLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:gravity="start|top">

    <View
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Lorem ipsum" />

</com.wefika.flowlayout.FlowLayout>

For detail implementation follow below link-

https://github.com/blazsolar/FlowLayout

You can try this links too:- https://github.com/xiaofeng-han/AndroidLibs/tree/master/flowlayoutmanager (try this) https://github.com/ApmeM/android-flowlayout https://gist.github.com/hzqtc/7940858

Czardom answered 17/12, 2016 at 6:7 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.