Shehabic
Shehabic

Reputation: 6877

How to inflate multiple instances of a layout with the same id inside an inflated layout

I have a LinearLayout with many nested LinearLayouts and TextViewss

My main activity inflates the main LinearLayout,

Then I load data from a server and based on the data received, I add multiple Layouts in a place holder (LinearLayout)

This is simple a news page where I load Images associated with the news and place it inside an initially empty LinearLayout.

Each Image has the following info: Title(TextView), Date(TextView), Image(ImageView) so what I actually do is the following:

*Please notice that this is only the essential coded in the question I elemenated all the try -> catch ... if/else ....etc

public void addImages(JSONArray images){
      ViewGroup vg = (ViewGroup) findViewById(R.id.imagesPlaceHolder);


      // loop on images
      for(int i =0;i<images.length;i++){

          View v = getLayoutInflater().inflate(R.layout.image_preview,vg);
          // then 
          I think that here is the problem 
          ImageView imv = (ImageView) v.findViewById(R.id.imagePreview);
          TextView dt = (TextView) v.findViewById(R.id.dateHolder);
          TextView ttl = (TextView) v.findViewById(R.id.title);
          // then 
          dt.setText("blablabla");
          ttl.setText("another blablabla");
          // I think the problem is here too, since it's referring to a single image
          imv.setTag( images.getJSONObject(i).getString("image_path").toString() );
          // then Image Loader From Server or Cache to the Image View

      }
}

The code above works good for a single image

But for multiple images the Image Loader doesn't work I guess it's because all ImageViews (Inflated multiple times) have the same ID

Upvotes: 27

Views: 17560

Answers (4)

Infomaster
Infomaster

Reputation: 873

I inflate XML-Layout with dynnamic and get text of id

  private val onAddView = View.OnClickListener {
    val parent = viewForm.findViewById<LinearLayout>(R.id.layout_parent)
    LayoutInflater.from(activity).inflate(R.layout.layout_child, parent) // layout_child has id "tv_attribute"
  }

  private val onSave = View.OnClickListener {
    val parent = viewForm.findViewById<LinearLayout>(R.id.layout_parent)
    for (i in 0 until parent.childCount) {
        val getText = parent.getChildAt(i).findViewById<TextView>(R.id.tv_attribute).text
    }
  }

Upvotes: 0

Ben Clayton
Ben Clayton

Reputation: 82219

I had the same problem, and based on the answer from @SylvainL, here'a a working solution:

// myContext is, e.g. the Activity.
// my_item_layout has a TextView with id='text'
// content is the parent view (e.g. your LinearLayoutView)
// false means don't add direct to the root
View inflated = LayoutInflater.from(myContext).inflate(R.layout.my_item_layout, content, false);

// Now, before we attach the view, find the TextView inside the layout.
TextView tv = (TextView) inflated.findViewById(R.id.text);
tv.setText(str);

// now add to the LinearLayoutView.
content.addView(inflated);

Upvotes: 22

SylvainL
SylvainL

Reputation: 3938

When you provide a ViewGroup to be used as the parent, the View returned by inflate() is this parent (vg in your case) and not the newly created View. Therefore, v points toward the ViewGroup vg and not toward the newly created View and as all of your children have the same id, the same subviews (imv, dt, ttl) are returned each time.

Two solutions. The first one is to change their id right after you are finished with them, before the next iteration. Therefore, on the next creation at the beginning of the next iteration, the newly created Views will have a different IDs from the older Views because they will still use the old constant defined in R.

The other solution would be to add the parameter false to the call to inflate() so that the newly created view will not be attached to the ViewGroup and will then be returned by the inflate() function instead of the ViewGroup. The rest of your code will then works as attended with the exception that you will have to attach them to the ViewGroup at the end of the iteration.

Notice that you still need to provide a ViewGroup because it will be used to determine the value of the LayoutParams.

Upvotes: 39

user697495
user697495

Reputation: 590

Is there a reason why the ImageView in the layout XML needs to have an ID? Could you erase the android:id attributes from the image_preview.xml layout and then simply iterate through the children of the inflated LinearLayout? For example:

ViewGroup v = (ViewGroup)getLayoutInflater().inflate(R.layout.image_preview,vg);
ImageView imv = (ImageView) v.getChildAt(0);    
TextView dt = (TextView) v.getChildAt(1);
TextView ttl = (TextView) v.getChildAt(2);

Upvotes: 9

Related Questions