If you use a
https://nishantvnair.wordpress.com/2010/09/28/flowlayout-in-android
UPDATE: For the latest version of the
https://bitbucket.org/adilson05uk/android-utils
LinearLayout
which has horizontal orientation and limited width, you'll notice that the child views you add to this LinearLayout
are placed one after another left-to-right up to and beyond the width of the LinearLayout
. The child views will not wrap to a new line and there is no native layout to do this. So! I've wrote one, as below. It's an adaptation of a view I found on Nishant Nair's Blog here:https://nishantvnair.wordpress.com/2010/09/28/flowlayout-in-android
UPDATE: For the latest version of the
HorizontalFlowLayout
class, see this repository:https://bitbucket.org/adilson05uk/android-utils
/**
* Custom view which extends {@link RelativeLayout}
* and which places its children horizontally,
* flowing over to a new line whenever it runs out of width.
*/
public class HorizontalFlowLayout extends RelativeLayout {
/**
* Constructor to use when creating View from code.
*/
public HorizontalFlowLayout(Context context) {
super(context);
}
/**
* Constructor that is called when inflating View from XML.
*/
public HorizontalFlowLayout(Context context, AttributeSet attrs) {
super(context, attrs);
}
/**
* Perform inflation from XML and apply a class-specific base style.
*/
public HorizontalFlowLayout(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
// need to call super.onMeasure(...) otherwise get some funny behaviour
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
final int width = MeasureSpec.getSize(widthMeasureSpec);
int height = MeasureSpec.getSize(heightMeasureSpec);
// increment the x position as we progress through a line
int xpos = getPaddingLeft();
// increment the y position as we progress through the lines
int ypos = getPaddingTop();
// the height of the current line
int line_height = 0;
// go through children
// to work out the height required for this view
// call to measure size of children not needed I think?!
// getting child's measured height/width seems to work okay without it
//measureChildren(widthMeasureSpec, heightMeasureSpec);
View child;
MarginLayoutParams childMarginLayoutParams;
int childWidth, childHeight, childMarginLeft, childMarginRight, childMarginTop, childMarginBottom;
for (int i = 0; i < getChildCount(); i++) {
child = getChildAt(i);
if (child.getVisibility() != GONE) {
childWidth = child.getMeasuredWidth();
childHeight = child.getMeasuredHeight();
if (child.getLayoutParams() != null
&& child.getLayoutParams() instanceof MarginLayoutParams) {
childMarginLayoutParams = (MarginLayoutParams)child.getLayoutParams();
childMarginLeft = childMarginLayoutParams.leftMargin;
childMarginRight = childMarginLayoutParams.rightMargin;
childMarginTop = childMarginLayoutParams.topMargin;
childMarginBottom = childMarginLayoutParams.bottomMargin;
}
else {
childMarginLeft = 0;
childMarginRight = 0;
childMarginTop = 0;
childMarginBottom = 0;
}
if (xpos + childMarginLeft + childWidth + childMarginRight + getPaddingRight() > width) {
// this child will need to go on a new line
xpos = getPaddingLeft();
ypos += line_height;
line_height = childMarginTop + childHeight + childMarginBottom;
}
else {
// enough space for this child on the current line
line_height = Math.max(
line_height,
childMarginTop + childHeight + childMarginBottom);
}
xpos += childMarginLeft + childWidth + childMarginRight;
}
}
ypos += line_height + getPaddingBottom();
if (MeasureSpec.getMode(heightMeasureSpec) == MeasureSpec.UNSPECIFIED) {
// set height as measured since there's no height restrictions
height = ypos;
}
else if (MeasureSpec.getMode(heightMeasureSpec) == MeasureSpec.AT_MOST
&& ypos < height) {
// set height as measured since it's less than the maximum allowed
height = ypos;
}
setMeasuredDimension(width, height);
}
@Override
protected void onLayout(boolean changed, int l, int t, int r, int b) {
// increment the x position as we progress through a line
int xpos = getPaddingLeft();
// increment the y position as we progress through the lines
int ypos = getPaddingTop();
// the height of the current line
int line_height = 0;
View child;
MarginLayoutParams childMarginLayoutParams;
int childWidth, childHeight, childMarginLeft, childMarginRight, childMarginTop, childMarginBottom;
for (int i = 0; i < getChildCount(); i++) {
child = getChildAt(i);
if (child.getVisibility() != GONE) {
childWidth = child.getMeasuredWidth();
childHeight = child.getMeasuredHeight();
if (child.getLayoutParams() != null
&& child.getLayoutParams() instanceof MarginLayoutParams) {
childMarginLayoutParams = (MarginLayoutParams)child.getLayoutParams();
childMarginLeft = childMarginLayoutParams.leftMargin;
childMarginRight = childMarginLayoutParams.rightMargin;
childMarginTop = childMarginLayoutParams.topMargin;
childMarginBottom = childMarginLayoutParams.bottomMargin;
}
else {
childMarginLeft = 0;
childMarginRight = 0;
childMarginTop = 0;
childMarginBottom = 0;
}
if (xpos + childMarginLeft + childWidth + childMarginRight + getPaddingRight() > r - l) {
// this child will need to go on a new line
xpos = getPaddingLeft();
ypos += line_height;
line_height = childHeight + childMarginTop + childMarginBottom;
}
else {
// enough space for this child on the current line
line_height = Math.max(
line_height,
childMarginTop + childHeight + childMarginBottom);
}
child.layout(
xpos + childMarginLeft,
ypos + childMarginTop,
xpos + childMarginLeft + childWidth,
ypos + childMarginTop + childHeight);
xpos += childMarginLeft + childWidth + childMarginRight;
}
}
}
}
15 comments:
thank you very much!
the most useful code for FlowLayout for Android I have found so far in the web!
just a single class and the trick is done, no exceptions or errors so far :D
I just wanted to say THANK YOU for this invaluable peace of code :)
Thanks a lot!!the best one.
Is there a specific credit line you would like us to add when we use this code?
No, it's fine. You can put in a link to this Blog post if you like but you don't have to.
How can I make the children be horizontal centred in this layout?
Hi Ravil, I've not tried that. You could try setting a "center" value for the "gravity" attribute. Otherwise you might have to play around with and customise the view further.
Adil, thanks for your reply. Setting a "center" value for the "gravity" attribute of layout doesn't work for me. Do you have any thoughts on further customizing it?
Hi Ravil, looking at the code it looks like you're going to have to calculate exactly where to place each child view if you want them centre-aligned rather than left-aligned. I can't see a quick fix unfortunately.
A code that "works" ..
Thanks a lot buddy !!!
hi
thanks for you code.
how can i start to add textview from right to left in this flowlayout.
thanks.
Hi Wali, the implementation as is assumes left-to-right placement of sub-views. To allow for right-to-left placement you'll have to modify the onMeasure(...) and onLayout(...) methods to do what you want. Now that you mention it, I'll probably modify the HorizontalFlowLayout view to do this but I won't get time to do so any time soon unfortunately :-(
how can i use this class for placing dynamically produced buttons in a linear layout?
Hossein, you add views to it like you would any other LinearLayout or RelativeLayout by calling one of its addView(...) methods.
nice blog.
Post a Comment