Search code examples
androidandroid-linearlayoutandroid-relativelayoutviewgroupflowlayout

Create ViewGroup of ImageView and TextView and display it in FlowLayout Programmatically - Android


I have a Flow layout that display 4 objects for row, but I need display these 4 objects with a textview below each one of them. But it display 2 images and 2 textview, and junp to another row. I tryed to create a ViewGroup to display them together, but I got the same isue. Maybe if I try to set location of the textView inside of the group It canal work, but I dont know How to do it.

What I got: What I got:

What I want: What I want:

My XML:

<ScrollView
    android:id="@+id/svLikes"
    android:layout_width="0dp"
    android:layout_height="0dp"
    android:layout_marginBottom="60dp"
    android:layout_marginEnd="14dp"
    android:layout_marginStart="14dp"
    android:layout_marginTop="48dp"
    android:background="#3c4052"
    android:orientation="vertical"
    app:layout_constraintBottom_toBottomOf="parent"
    app:layout_constraintLeft_toLeftOf="parent"
    app:layout_constraintRight_toRightOf="parent"
    app:layout_constraintTop_toTopOf="@+id/btnAdd"
    app:layout_constraintVertical_bias="0.0"
    tools:layout_constraintBottom_creator="1"
    tools:layout_constraintLeft_creator="1"
    tools:layout_constraintRight_creator="1"
    tools:layout_constraintTop_creator="1">

    <com.nex3z.flowlayout.FlowLayout
        xmlns:app="http://schemas.android.com/apk/res-auto"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:paddingTop="5dp"
        android:paddingRight="5dp"
        app:childSpacingForLastRow="align"
        android:paddingLeft="5dp"
        app:rowSpacing="8dp"
        android:id="@+id/likesContainer"
        >

    </com.nex3z.flowlayout.FlowLayout>

</ScrollView>

My code:

ImageView iconLike = new ImageView(Register30.this);
            TextView txtLike = new TextView(Register30.this);

            iconLike.setImageDrawable(getDrawable(R.drawable.x));
            txtLike.setText("Unable");


            countLikesAdd++;
            removeMessageOrShow();


            LinearLayout.LayoutParams lp = new LinearLayout.LayoutParams(140,130);
            lp.setMargins(5,5,5,5);
            iconLike.setLayoutParams(lp);
            txtLike.setLayoutParams(lp);
            txtLike.setTextColor(Color.parseColor("#FFFFFF"));
            fieldLike.setText("");
            ViewGroup gp = new LinearLayout(Register30.this);
            gp.addView(iconLike);
            gp.addView(txtLike);
            likesContainer.addView(gp);

Solution

  • First Method : Static Way I think what you need is a drawable image on TextView. The drawable image can be inserted in any position except center. Create a suitable image of required sizes form asset studio and use this line on TextView.

    android:drawableTop="@drawable/ic_fb_logo_blue_48dp"

    A simple implementation is written in below code.

    <android.support.v4.widget.NestedScrollView
                    android:id="@+id/svLikes"
                    android:layout_width="match_parent"
                    android:layout_height="match_parent"
                    android:layout_marginBottom="60dp"
                    android:layout_marginEnd="14dp"
                    android:layout_marginStart="14dp"
                    android:layout_marginTop="48dp"
                    android:orientation="vertical">
    
                    <com.nex3z.flowlayout.FlowLayout
                        android:id="@+id/likesContainer"
                        android:layout_width="match_parent"
                        android:layout_height="wrap_content"
                        android:paddingLeft="5dp"
                        android:paddingRight="5dp"
                        android:paddingTop="5dp"
                        app:childSpacingForLastRow="align"
                        app:rowSpacing="8dp">
    
                        <TextView
                            android:layout_width="wrap_content"
                            android:layout_height="wrap_content"
                            android:drawableTop="@drawable/ic_fb_logo_blue_48dp"
                            android:gravity="center"
                            android:text="@string/facebook"
                            android:textSize="16sp" />
    
                        <TextView
                            android:layout_width="wrap_content"
                            android:layout_height="wrap_content"
                            android:drawableTop="@drawable/ic_fb_logo_blue_48dp"
                            android:gravity="center"
                            android:text="@string/facebook"
                            android:textSize="16sp" />
    
                        <TextView
                            android:layout_width="wrap_content"
                            android:layout_height="wrap_content"
                            android:drawableTop="@drawable/ic_fb_logo_blue_48dp"
                            android:gravity="center"
                            android:text="@string/facebook"
                            android:textSize="16sp" />
    
                        <TextView
                            android:layout_width="wrap_content"
                            android:layout_height="wrap_content"
                            android:drawableTop="@drawable/ic_fb_logo_blue_48dp"
                            android:gravity="center"
                            android:text="@string/facebook"
                            android:textSize="16sp" />
    
                    </com.nex3z.flowlayout.FlowLayout>
    
                </android.support.v4.widget.NestedScrollView>
    

    The output image is below. I have used NestedScrollView Instead of ScrollView. enter image description here

    Second Method : Dynamic Programmatically a number of views can be generated by using grid layout. My implemenation using recylerview is below

    Inside Activity class:

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        toolbar = (Toolbar) findViewById(R.id.toolbar);
        setSupportActionBar(toolbar);
    
        recyclerOne = (RecyclerView) findViewById(R.id.recyclerView);
    
        initRecyclerView();
    
        //update whenever necessary
        adapterOne.updateItems(myList);
    }
    
    private void initRecyclerView(){
        //Datum is model class
        int spanCount = 4; // 4 columns in grid
        int spacing = 8;
        boolean includeEdge = true;
    
        GridLayoutManager gridLayoutManager = new GridLayoutManager(mContext, spanCount);
        recyclerOne.setHasFixedSize(false);
        recyclerOne.setLayoutManager(gridLayoutManager);
        recyclerOne.addItemDecoration(new GridSpacingItemDecoration(spanCount, spacing, includeEdge));
        adapterOne = new RecylcerViewAdapter(new ArrayList<Datum>());
        recyclerOne.setAdapter(adapterOne);
    }
    

    The GridSpacingItemDecoration class is

    public class GridSpacingItemDecoration extends RecyclerView.ItemDecoration {
    
    private int spanCount;
    private int spacing;
    private boolean includeEdge;
    
    public GridSpacingItemDecoration(int spanCount, int spacing, boolean includeEdge) {
        this.spanCount = spanCount;
        this.spacing = spacing;
        this.includeEdge = includeEdge;
    }
    
    @Override
    public void getItemOffsets(Rect outRect, View view, RecyclerView parent, RecyclerView.State state) {
        int position = parent.getChildAdapterPosition(view); // item position
        int column = position % spanCount; // item column
    
        if (includeEdge) {
            outRect.left = spacing - column * spacing / spanCount; // spacing - column * ((1f / spanCount) * spacing)
            outRect.right = (column + 1) * spacing / spanCount; // (column + 1) * ((1f / spanCount) * spacing)
    
            if (position < spanCount) { // top edge
                outRect.top = spacing;
            }
            outRect.bottom = spacing; // item bottom
        } else {
            outRect.left = column * spacing / spanCount; // column * ((1f / spanCount) * spacing)
            outRect.right = spacing - (column + 1) * spacing / spanCount; // spacing - (column + 1) * ((1f /    spanCount) * spacing)
            if (position >= spanCount) {
                outRect.top = spacing; // item top
            }
        }
    }
    

    }

    Inside recycler view adapter class, during binding view use a single textview with drawable image as in first method and update data. For updating whole list you create following function and call it from activity class:

    public void updateItems(List<Datum> data) {
        list.clear()
        list.addAll(data)
        notifyDataSetChanged();
    }
    

    Other methods There is also one other method I know which is done by inflating an item and adding the inflated view on the already created linearlayout(or any other container layouts).

    Use whatever methods you like. Enjoy coding!