Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Android - LinearLayout Horizontal with wrapping children

Tags:

android

Is there a property to set for Android's LinearLayout that will enable it to properly wrap child controls?

Meaning - I have changeable number of children and would like to lay out them horizontally like:

Example: Control1, Control2, Control3, ...

I do that by setting:

ll.setOrientation(LinearLayout.HORIZONTAL);
foreach (Child c in children)
  ll.addView(c);

However, if I have large number of children, last one gets cuts off, instead of going to next line.

Any idea how this can be fixed?

like image 677
nikib3ro Avatar asked Jun 02 '10 21:06

nikib3ro


4 Answers

As of May 2016 Google has created its own FlexBoxLayout which should solve your problem.

You can find the GitHub repo here: https://github.com/google/flexbox-layout

like image 98
mysteryhobo Avatar answered Sep 23 '22 21:09

mysteryhobo


This should be what you want:

import android.content.Context; import android.util.AttributeSet; import android.view.View; import android.view.ViewGroup;  /**  *  * @author RAW  */ public class FlowLayout extends ViewGroup {      private int line_height;      public static class LayoutParams extends ViewGroup.LayoutParams {          public final int horizontal_spacing;         public final int vertical_spacing;          /**          * @param horizontal_spacing Pixels between items, horizontally          * @param vertical_spacing Pixels between items, vertically          */         public LayoutParams(int horizontal_spacing, int vertical_spacing) {             super(0, 0);             this.horizontal_spacing = horizontal_spacing;             this.vertical_spacing = vertical_spacing;         }     }      public FlowLayout(Context context) {         super(context);     }      public FlowLayout(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) - getPaddingLeft() - getPaddingRight();         int height = MeasureSpec.getSize(heightMeasureSpec) - getPaddingTop() - getPaddingBottom();         final int count = getChildCount();         int line_height = 0;          int xpos = getPaddingLeft();         int ypos = getPaddingTop();          int childHeightMeasureSpec;         if (MeasureSpec.getMode(heightMeasureSpec) == MeasureSpec.AT_MOST) {             childHeightMeasureSpec = MeasureSpec.makeMeasureSpec(height, MeasureSpec.AT_MOST);         } else {             childHeightMeasureSpec = MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED);         }           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), childHeightMeasureSpec);                 final int childw = child.getMeasuredWidth();                 line_height = Math.max(line_height, child.getMeasuredHeight() + lp.vertical_spacing);                  if (xpos + childw > width) {                     xpos = getPaddingLeft();                     ypos += line_height;                 }                  xpos += childw + lp.horizontal_spacing;             }         }         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 ViewGroup.LayoutParams generateDefaultLayoutParams() {         return new LayoutParams(1, 1); // default of 1px spacing     }      @Override     protected android.view.ViewGroup.LayoutParams generateLayoutParams(         android.view.ViewGroup.LayoutParams p) {         return new LayoutParams(1, 1, p);     }      @Override     protected boolean checkLayoutParams(ViewGroup.LayoutParams p) {         if (p instanceof LayoutParams) {             return true;         }         return false;     }      @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.horizontal_spacing;             }         }     } } 

and the XML file

/* you must write your package name and class name */ <org.android.FlowLayout                 android:id="@+id/flow_layout"                 android:layout_marginLeft="5dip"                 android:layout_width="fill_parent"                 android:layout_height="wrap_content"/> 
like image 32
Randy Sugianto 'Yuku' Avatar answered Sep 23 '22 21:09

Randy Sugianto 'Yuku'


For anyone who needs this kind of behaviour:

private void populateLinks(LinearLayout ll, ArrayList<Sample> collection, String header) {

    Display display = getWindowManager().getDefaultDisplay();
    int maxWidth = display.getWidth() - 10;

    if (collection.size() > 0) {
        LinearLayout llAlso = new LinearLayout(this);
        llAlso.setLayoutParams(new LayoutParams(LayoutParams.FILL_PARENT,
                LayoutParams.WRAP_CONTENT));
        llAlso.setOrientation(LinearLayout.HORIZONTAL);

        TextView txtSample = new TextView(this);
        txtSample.setText(header);

        llAlso.addView(txtSample);
        txtSample.measure(0, 0);

        int widthSoFar = txtSample.getMeasuredWidth();
        for (Sample samItem : collection) {
            TextView txtSamItem = new TextView(this, null,
                    android.R.attr.textColorLink);
            txtSamItem.setText(samItem.Sample);
            txtSamItem.setPadding(10, 0, 0, 0);
            txtSamItem.setTag(samItem);
            txtSamItem.setOnClickListener(new OnClickListener() {
                @Override
                public void onClick(View v) {
                    TextView self = (TextView) v;
                    Sample ds = (Sample) self.getTag();

                    Intent myIntent = new Intent();
                    myIntent.putExtra("link_info", ds.Sample);
                    setResult("link_clicked", myIntent);
                    finish();
                }
            });

            txtSamItem.measure(0, 0);
            widthSoFar += txtSamItem.getMeasuredWidth();

            if (widthSoFar >= maxWidth) {
                ll.addView(llAlso);

                llAlso = new LinearLayout(this);
                llAlso.setLayoutParams(new LayoutParams(
                        LayoutParams.FILL_PARENT,
                        LayoutParams.WRAP_CONTENT));
                llAlso.setOrientation(LinearLayout.HORIZONTAL);

                llAlso.addView(txtSamItem);
                widthSoFar = txtSamItem.getMeasuredWidth();
            } else {
                llAlso.addView(txtSamItem);
            }
        }

        ll.addView(llAlso);
    }
}
like image 21
nikib3ro Avatar answered Sep 22 '22 21:09

nikib3ro


Old question, but in case someone ends up here, two libraries that do exactly that:

https://github.com/blazsolar/FlowLayout

https://github.com/ApmeM/android-flowlayout

like image 44
kito Avatar answered Sep 22 '22 21:09

kito