Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Android which layout to use to overflow objects to the next line

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.

like image 707
Zapnologica Avatar asked Sep 13 '13 06:09

Zapnologica


2 Answers

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>
like image 92
Pravin Sonawane Avatar answered Oct 16 '22 16:10

Pravin Sonawane


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

like image 20
Mrinmoy Avatar answered Oct 16 '22 18:10

Mrinmoy