Dynamically add layout to another layout

user5590200

I have a RecyclerView adapter. Within the onBindViewHolder, I check how many images each item passed to the adapter has. Depending on the number of images, I want to load/inflate a child layout into the main layout.

For example:

  • If the item has 1 image, I need to inflate images_one.xml into the main layout
  • If the item has 2 images, I need to inflate images_two.xml into the main layout
  • etc, up to 8 images (images_eight.xml)

Here is the main layout, main_layout.xml:

<LinearLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <TextView
        android:id="@+id/title"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        />

    // INFLATE CHILD LAYOUT HERE (images_one.xml, images_two.xml, etc.)

    <TextView
        android:id="@+id/desc"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        />

</LinearLayout>

And here is one of the child layouts that need to be inflated into the main layout, images_two.xml:

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:orientation="vertical">

    <ImageView
        android:id="@+id/image_one"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        />

    <ImageView
        android:id="@+id/image_two"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        />

</LinearLayout>

And lastly, here is my RecyclerView adapter:

public class RecyclerAdapter extends RecyclerView.Adapter<RecyclerAdapter.ViewHolder> {

    private static Context context;
    private List<Message> mDataset;

    public RecyclerAdapter(Context context, List<Message> myDataset) {
        this.context = context;
        this.mDataset = myDataset;
    }

    public static class ViewHolder extends RecyclerView.ViewHolder implements View.OnCreateContextMenuListener, View.OnClickListener {
        public TextView title;
        public TextView desc;

        public ViewHolder(View view) {
            super(view);
            view.setOnCreateContextMenuListener(this);

            title = (TextView) view.findViewById(R.id.title);
            desc = (TextView) view.findViewById(R.id.desc);
        }
    }

    @Override
    public RecyclerAdapter.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
        View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.main_layout, parent, false);
        ViewHolder vh = new ViewHolder((LinearLayout) view);

        return vh;
    }

    @Override
    public void onBindViewHolder(ViewHolder holder, int position) {
        Message item = mDataset.get(position);

        holder.title.setText(item.getTitle());
        holder.desc.setText(item.getDesc());

        int numImages = item.getImages().size();

        if (numImages == 1) {
            // Inflate images_one.xml into main_layout.xml
        } else if (numImages == 2) {
            // Inflate images_two.xml into main_layout.xml
        } else if (numImages == 3) {
            // Inflate images_three.xml into main_layout.xml
        }
        // ETC...
    }

    @Override
    public int getItemCount() {
        return mDataset.size();
    }

}

What's the best way of implementing this?

kris larson

The way Android intends ViewHolders to be used is for views to be created/inflated in onCreateViewHolder() then filled with adapter data in onBindViewHolder(). This is important because onCreateViewHolder() is only called when there is nothing to recycle.

Unlike ListView, RecyclerView is actually recycling ViewHolders rather than Views. So trying to inflate views in onBindViewHolder() is not going to work.

Notice that viewType parameter in onCreateViewHolder()? That's the key.

First you need to override getItemViewType() in your adapter. Let's take a shortcut here; since the view type is an int, let's just use the number of images in the item as the view type:

    @Override
    public int getItemViewType(int position) {
        //  ... return the number of images for data at position
    }

(Normally I would define final ints like VIEW_TYPE_ONE_IMAGE etc. to be returned, which is the proper way to do it.)

How does the adapter use the view types? If your data at position 0 has a view type of 4, then the RecyclerView will only pass a ViewHolder created in onCreateViewHolder() with viewType == 4 to onBindViewHolder() with position == 0.

Now your onCreateViewHolder() might look like this:

    @Override
    public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {

        View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.main_layout, parent, false);
        return new ViewHolder(view, viewType);
    }

(FYI: The return type for onCreateViewHolder() should be your ViewHolder type, not RecyclerViews.)

Notice that I added a viewType parameter to your ViewHolder constructor:

    public static class ViewHolder extends RecyclerView.ViewHolder implements View.OnCreateContextMenuListener, View.OnClickListener {
        public TextView title;
        public TextView desc;
        public ImageView img1;
        public ImageView img2;

        public ViewHolder(View view, int viewType) {
            super(view);
            view.setOnCreateContextMenuListener(this);

            title = (TextView) view.findViewById(R.id.title);
            desc = (TextView) view.findViewById(R.id.desc);

            ViewGroup placeholder = (ViewGroup) view.findViewById(R.id.placeholder);

            // here you can use the viewType to help you figure 
            // out which child views you need references for
            switch (viewType) {
            case 1:
                // ...
                break;

            case 2:
                LayoutInflater.from(parent.getContext()).inflate(R.layout.images_two, placeholder);       // this combines inflate() and addView()
                img1 = placeholder.findViewById(R.id.image_one);
                img2 = placeholder.findViewById(R.id.image_two);
                break;

            // ...
            }
        }
    }

You don't necessarily need viewType in the constructor if you are using the same ids in all your different views; you can just check if they're null in onBindViewHolder().


If you have many different view types, one great way to organize the create/bind code is to make your ViewHolder subclass abstract, further subclass it into a different type for each view type, and then return an instance of the appropriate type in onCreateViewHolder(). Declare an abstract method like public void bind(YourItemType item) in your abstract type and implement in your subclasses, then your onBindViewHolder() method is just:

    @Override
    public void onBindViewHolder(ViewHolder holder, int position) {
        holder.bind(data.get(position));  // ... or however you access an item at position
    }

...and creating looks like:

    @Override
    public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {

        View view = null;

        switch (viewType) {
        case 1:
            view = LayoutInflater.from(parent.getContext()).inflate(R.layout.images_one, parent, false);
            return new OneImageViewHolder(view);

        case 2:
            view = LayoutInflater.from(parent.getContext()).inflate(R.layout.images_two, parent, false);
            return new TwoImageViewHolder(view);

        // ... etc. etc.
        }
    }

Don't forget, you may be passed a recycled ViewHolder in onBindViewHolder(), so you have to assume all your views are "dirty" and set every single child view to a known state for the data at position.

Collected from the Internet

Please contact [email protected] to delete if infringement.

edited at
0

Comments

0 comments
Login to comment

Related

From Dev

IllegalStateException when add a layout into another layout with LayoutInflater

From Dev

Dynamically add element to layout

From Dev

Add a xml layout multiple into another xml with scrollview

From Dev

Add Buttons to Relative Layout Dynamically or Extended Linear Layout android

From Dev

Dynamically include another layout in Fragment Activity

From Dev

Add a TextView dynamically in a layout ANDROID

From Dev

Android Add Layout View to another Layout programatically

From Dev

Add EditText to another LinearLayout from non children layout dynamically

From Dev

add Layout programmatically inside another one

From Dev

Row cannot add dynamically using code to Table Layout in Android

From Dev

How to dynamically add ImageView to layout using Adapter

From Dev

Android: How to dynamically add a "Custom View" into a linear layout

From Dev

Add nodes dynamically to a D3 Tree layout request (on toggle)

From Dev

Add another layout in Lubuntu

From Dev

Dynamically add content to layout in MVC4

From Dev

Add a layout dynamically, to overlapp the other layout

From Dev

Add another layout in Lubuntu

From Dev

Set a layout over another layout

From Dev

Add Buttons to Relative Layout Dynamically or Extended Linear Layout android

From Dev

Dynamically include another layout in Fragment Activity

From Dev

Dynamically add Layout after some layout?

From Dev

Android Add Layout View to another Layout programatically

From Dev

How to add this type of layout dynamically (android)

From Dev

How to add the layout dynamically

From Dev

Layout overlaying another layout after dynamically change

From Dev

How to add Layout on top of another Layout?

From Dev

How to add 2 fragments dynamically in a single layout?

From Dev

Dynamically add QWebEngineView to layout

From Dev

Use layout as background of another layout

Related Related

  1. 1

    IllegalStateException when add a layout into another layout with LayoutInflater

  2. 2

    Dynamically add element to layout

  3. 3

    Add a xml layout multiple into another xml with scrollview

  4. 4

    Add Buttons to Relative Layout Dynamically or Extended Linear Layout android

  5. 5

    Dynamically include another layout in Fragment Activity

  6. 6

    Add a TextView dynamically in a layout ANDROID

  7. 7

    Android Add Layout View to another Layout programatically

  8. 8

    Add EditText to another LinearLayout from non children layout dynamically

  9. 9

    add Layout programmatically inside another one

  10. 10

    Row cannot add dynamically using code to Table Layout in Android

  11. 11

    How to dynamically add ImageView to layout using Adapter

  12. 12

    Android: How to dynamically add a "Custom View" into a linear layout

  13. 13

    Add nodes dynamically to a D3 Tree layout request (on toggle)

  14. 14

    Add another layout in Lubuntu

  15. 15

    Dynamically add content to layout in MVC4

  16. 16

    Add a layout dynamically, to overlapp the other layout

  17. 17

    Add another layout in Lubuntu

  18. 18

    Set a layout over another layout

  19. 19

    Add Buttons to Relative Layout Dynamically or Extended Linear Layout android

  20. 20

    Dynamically include another layout in Fragment Activity

  21. 21

    Dynamically add Layout after some layout?

  22. 22

    Android Add Layout View to another Layout programatically

  23. 23

    How to add this type of layout dynamically (android)

  24. 24

    How to add the layout dynamically

  25. 25

    Layout overlaying another layout after dynamically change

  26. 26

    How to add Layout on top of another Layout?

  27. 27

    How to add 2 fragments dynamically in a single layout?

  28. 28

    Dynamically add QWebEngineView to layout

  29. 29

    Use layout as background of another layout

HotTag

Archive