androidtag-cloud

Create Tag Cloud


I need to create a basic Tag Cloud. My aim is to add multiple TextView(Tags) that automatically fits themselves in a new line if the number exceeds the device width. (Like Instagram).

Right now when the width of the layout containing (TextView)tags exceeds the (device width) the TextView(s) at the end wraps itself. the TextView at the last gets distorted

I tried using RelativeLayout but i am unable to figure out the logic. I viewed this post but if there is a better or simply a cleaner solution.

Thanks for your precious time.

It is not necessary that the result looks like Instagram. what i want to achieve


Solution

  • The cleaner solution is to write your own custom ViewGroup class. Find the sample below.

    For a complete descriptive explanation visit, How to Create Custom Layout in Android by Extending ViewGroup Class.

    public class TagLayout extends ViewGroup {
    
        public TagLayout(Context context) {
            super(context);
        }
    
        public TagLayout(Context context, AttributeSet attrs) {
            super(context, attrs);
        }
    
        public TagLayout(Context context, AttributeSet attrs, int defStyleAttr) {
            super(context, attrs, defStyleAttr);
        }
    
    
        @Override
        protected void onLayout(boolean changed, int l, int t, int r, int b) {
            final int count = getChildCount();
            int curWidth, curHeight, curLeft, curTop, maxHeight;
    
            //get the available size of child view
            final int childLeft = this.getPaddingLeft();
            final int childTop = this.getPaddingTop();
    
            final int childRight = this.getMeasuredWidth() - this.getPaddingRight();
            final int childBottom = this.getMeasuredHeight() - this.getPaddingBottom();
    
            final int childWidth = childRight - childLeft;
            final int childHeight = childBottom - childTop;
    
            maxHeight = 0;
            curLeft = childLeft;
            curTop = childTop;
            for (int i = 0; i < count; i++) {
                View child = getChildAt(i);
                if (child.getVisibility() == GONE)
                    return;
    
                //Get the maximum size of the child
                child.measure(MeasureSpec.makeMeasureSpec(childWidth, MeasureSpec.AT_MOST), MeasureSpec.makeMeasureSpec(childHeight, MeasureSpec.AT_MOST));
                curWidth = child.getMeasuredWidth();
                curHeight = child.getMeasuredHeight();
                //wrap is reach to the end
                if (curLeft + curWidth >= childRight) {
                    curLeft = childLeft;
                    curTop += maxHeight;
                    maxHeight = 0;
                }
                //do the layout
                child.layout(curLeft, curTop, curLeft + curWidth, curTop + curHeight);
                //store the max height
                if (maxHeight < curHeight)
                    maxHeight = curHeight;
                curLeft += curWidth;
            }
        }
    }
    

    To use the TagLayout, you can add it to your activity/fragment layout declaration. main_activity.xml

    <com.javatechig.taglayout.TagLayout
        android:id="@+id/tagLayout"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content" />
    

    Now we can have a custom view to allow some level of customization for each tag item layout.

    tag_layout.xml

    <TextView
        android:id="@+id/tagTextView"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_margin="5dp"
        android:background="#a000"
        android:padding="10dp"
        android:textColor="#fff" />
    

    MainActivity.java Finally, from activity class you can add the tag items as follows.

    public class MainActivity extends AppCompatActivity {
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);
    
            TagLayout tagLayout = (TagLayout) findViewById(R.id.tagLayout);
            LayoutInflater layoutInflater = getLayoutInflater();
            String tag;
            for (int i = 0; i <= 20; i++) {
                tag = "#tag" + i;
                View tagView = layoutInflater.inflate(R.layout.tag_layout, null, false);
    
                TextView tagTextView = (TextView) tagView.findViewById(R.id.tagTextView);
                tagTextView.setText(tag);
                tagLayout.addView(tagView);
            }
        }
    }
    

    Result

    enter image description here