4

I need to implement next UI element:

enter image description here

  • Unknown size list of strings (That came from a server call)
  • Any item should be wrap content.
  • If an item is not fits to row, he will be in the next row.
  • All list/grid is centered

I thought of using RecyclerView with StaggeredGridLayoutManager

But I don't know if it the right way, any ideas?

David
  • 37,109
  • 32
  • 120
  • 141
  • If your data is reasonably static, it might be easiest to extend ViewGroup, and override onLayout(). You would want to get the width of each child and position it in the right row accordingly. Can't say I've used StaggeredGridLayoutManager before, that might be fine too. – fractalwrench Dec 12 '15 at 21:50
  • Gaana app uses same UI for tags searched in the app. The data doesn't come from a server, but the data is not static either. May be you would like to check the app to get some clue – Green goblin Dec 12 '15 at 21:53
  • @fractalwrench and ^GreenGoblin Thanks, but as I mention in the question, the data is not static, and could be 1 string or 90. – David Dec 12 '15 at 21:56
  • In that case you would want to use RecylerView and subclass LayoutManager. – fractalwrench Dec 12 '15 at 22:12
  • @fractalwrench Ya, so what should be in this subclass of `LayoutManager` ? – David Dec 12 '15 at 22:25

2 Answers2

3

The fact that you have a varying number of cells in each row means you would have to work rather hard to get any value from a recycling approach. Because in order to know which data goes in row 17 you have to (pre) measure all the data in rows 0 - 16.

Depending on your use case. If the list is bounded at some reasonable number of items. Using a single TextView, with some clever use of spans may be a better solution. Just collect all your hashtags into a single string, and use RoundedBackgroundSpan (see link) to add the colored backgrounds. then wrap the whole thing in a ScrollView.

EDIT 1: Added possible solution code.

public class RoundedBackgroundSpan extends ReplacementSpan {

    int mBackgroundColor;
    int mTextColor;
    float mRoundedCornerRadius;
    float mSidePadding = 10; // play around with these as needed
    float mVerticalPadding = 30; // play around with these as needed

    public RoundedBackgroundSpan(final int backgroundColor, final int textColor, final float roundedCornerRadius)
    {
        mBackgroundColor = backgroundColor;
        mTextColor = textColor;
        mRoundedCornerRadius = roundedCornerRadius;
    }

    @Override
    public int getSize(final Paint paint, final CharSequence text, final int start, final int end, final Paint.FontMetricsInt fm)
    {
        return Math.round(MeasureText(paint, text, start, end) + (2 * mSidePadding));
    }

    @Override
    public void draw(final Canvas canvas, final CharSequence text, final int start, final int end, final float x, final int top, final int y, final int bottom, final Paint paint)
    {
        // draw the rounded rectangle background
        RectF rect = new RectF(x, -mVerticalPadding + ((bottom + top) / 2) + paint.getFontMetrics().top, x + MeasureText(paint, text, start, end) + (2 * mSidePadding), mVerticalPadding + ((bottom + top) / 2) + paint.getFontMetrics().bottom);
        paint.setColor(mBackgroundColor);
        canvas.drawRoundRect(rect, mRoundedCornerRadius, mRoundedCornerRadius, paint);
        // draw the actual text
        paint.setColor(mTextColor);
        canvas.drawText(text, start, end, x + mSidePadding, ((bottom + top) / 2), paint);
    }

    private float MeasureText(Paint paint, CharSequence text, int start, int end)
    {
        return paint.measureText(text, start, end);
    }

}

And somewhere else (activity / fragment most likely)

    SpannableStringBuilder stringBuilder = new SpannableStringBuilder();
    for (String hashTag : hashTags)
    {
        stringBuilder.append(hashTag);
        stringBuilder.setSpan(new RoundedBackgroundSpan(getRandomColor(), getResources().getColor(android.R.color.darker_gray), 10), stringBuilder.length() - hashTag.length(), stringBuilder.length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
        stringBuilder.append(" ");
    }

    textView.setText(stringBuilder);

And somewhere in your xml (note android:lineSpacingMultiplier="3" and android:gravity="center")

<ScrollView
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <TextView
        android:lineSpacingMultiplier="3"
        android:gravity="center"
        android:padding="10dp"
        android:id="@+id/text"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"/>

</ScrollView>
Community
  • 1
  • 1
Oren
  • 4,152
  • 3
  • 30
  • 37
3

I don't sure that method would be helpful for you, but instead of

using RecyclerView with StaggeredGridLayoutManager

you can use third-party FlowLayout:

  1. First implementation (Android flow layout)

    enter image description here enter image description here

  2. Second implementation (Flow layout)

    enter image description here

Check this gist for full example:

https://github.com/davidbeloo/Hashtags

enter image description here

David
  • 37,109
  • 32
  • 120
  • 141
Igor Tyulkanov
  • 5,487
  • 2
  • 32
  • 49