Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to create Flow TextView

Tags:

java

android

Working on app where user has to put some data in EditText, but in front and behind this EditText I have TextViews. For that I use (horizontal) LinearLayout where I put TextView EditText TextView. I faced with problem of line transfer. Please, help me to find a solution.

It looks like this now:

|blabla_______tatata|
|             tatata|

I need like this:

|blabla_______tatata|
|tatata             |

I tried to use FlowTextView but it didn't help, It looks ugly, usable for pictures only.

enter image description here

3rd way by using Flow Layout

The problem is: it moves to the second line if it doesn't have enough space. Please help me to make some correction here:

enter image description here

Manifest

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.example.nikolai.app">

    <application
        android:allowBackup="true"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:supportsRtl="true"
        android:theme="@style/AppTheme">
        <activity android:name=".MainActivity">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
    </application>

</manifest>

Main Activity

    public class MainActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
    }
}

HorizontalFlowLayout

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;
            }
        }
    }
}

My XML

    <?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    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.example.nikolai.app.MainActivity">

    <com.example.nikolai.app.HorizontalFlowLayout
        android:id="@+id/horizontal_flow_layout"
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:paddingLeft="@dimen/size_5"
        android:paddingRight="@dimen/size_5">


        <TextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:textSize="20dp"
            android:text="blablabla"/>

        <EditText
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:textSize="20dp"
            android:ems="7"/>
        <TextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:textSize="20dp"
            android:text="tatatatatatatatata"/>

    </com.example.nikolai.app.HorizontalFlowLayout>

</RelativeLayout>

enter image description here

like image 870
JohnPix Avatar asked Mar 29 '16 04:03

JohnPix


Video Answer


2 Answers

Here's full source code for FlowLayout with reference to actual author. I'm using this implementation and it works:

/**  @author RAW
 * @reference http://nishantvnair.wordpress.com/2010/09/28/flowlayout-in-android/
 * Some changes applied, i.e. default horz and vert spacings...
 * */

 public class FlowLayout extends ViewGroup {
    private static int DEFAULT_HORIZONTAL_SPACING=5;
    private static int DEFAULT_VERTICAL_SPACING=5;
    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) {
                int horizontal_spacing, vertical_spacing;
                final ViewGroup.LayoutParams lp = child.getLayoutParams();
                if(lp instanceof LayoutParams) {
                    horizontal_spacing=((LayoutParams )lp).horizontal_spacing;
                    vertical_spacing=((LayoutParams )lp).vertical_spacing;
                } else {
                    horizontal_spacing=DEFAULT_HORIZONTAL_SPACING;
                    vertical_spacing=DEFAULT_VERTICAL_SPACING;
                }
                child.measure(MeasureSpec.makeMeasureSpec(width, MeasureSpec.AT_MOST), childHeightMeasureSpec);
                final int childw = child.getMeasuredWidth();
                line_height = Math.max(line_height, child.getMeasuredHeight() + vertical_spacing);
                if (xpos + childw > width) {
                    xpos = getPaddingLeft();
                    ypos += line_height;
                }
                xpos += childw + 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 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 ViewGroup.LayoutParams lp = child.getLayoutParams();
                if (xpos + childw > width) {
                    xpos = getPaddingLeft();
                    ypos += line_height;
                }
                child.layout(xpos, ypos, xpos + childw, ypos + childh);
                if(lp instanceof LayoutParams)
                    xpos += childw + ((LayoutParams)lp).horizontal_spacing;
                else
                    xpos += childw + DEFAULT_HORIZONTAL_SPACING;
            }
        }
    }
}

Usage kinda:

<com.mydomain.FlowLayout
        android:id="@+id/recipientsList"
        android:layout_width="match_parent"
        android:layout_height="wrap_content" >
like image 177
Barmaley Avatar answered Sep 29 '22 15:09

Barmaley


Try this,

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;
      }
    }
  }
}

And use in XML Layout:

 <com.test.widget.HorizontalFlowLayout
            android:id="@+id/horizontal_flow_layout"
            android:layout_width="fill_parent"
            android:layout_height="wrap_content"
            android:paddingLeft="@dimen/size_5"
            android:paddingRight="@dimen/size_5">

 <TextView
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:paddingRight="5dp"
    android:textSize="20sp"
    android:text="блабла"
    android:id="@+id/textView1"/>

 <EditText
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:id="@+id/name"
    android:textSize="20sp"
    android:inputType="textCapSentences"
    android:ems="5"/>
</LinearLayout>
 </com.test.widget.HorizontalFlowLayout>
like image 27
Pradeep Gupta Avatar answered Sep 29 '22 16:09

Pradeep Gupta