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

4

27

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

Mariejeanne answered 3/2, 2013 at 1:14 Comment(2)
is there any reason why you are not using a listview ?Giacinta
Yes, I have a LinearLayout inside a Scrollview where I have some TextViews at the top, then I have many ImageViews, and Even Video Holders, ListView will have its own scroll inside a ScrollView, it'll be bad for usability (if I'm right)Mariejeanne
A
9

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);
Adios answered 3/2, 2013 at 1:59 Comment(1)
Yes, my view is nested with <FrameLayout> <ImageView /> <TextViews> </FrameLayout>Mariejeanne
I
39

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.

Icecold answered 3/2, 2013 at 6:3 Comment(5)
Well my solution above works, but what I'm afraid of is: how do I know if there are auto-generated integers in the range I'm using 1001 to 1000+x, or 2001 to 2000 + x. I've noticed that the Auto generated ids usually have very large value.Mariejeanne
Check it with findViewById(): it will return null if there is no ID with the required integer value. However, the important thing in your case is simply that the value (1000 + i) is different from R.id.imagePreview.Icecold
Changing the 'id' at the end of iteration did the trick.... :p still its like a patch :pAksoyn
@Shehabix if you want to use unused ids, View.generateViewId() is what you are looking for. "Generate a value suitable for use in setId(int). This value will not collide with ID values generated at build time by aapt for R.id."Indisposition
Both proposed solutions don't appear to work well if inflating a relative layout. When the ids are replaced the relative attributes (ex. toRightOf) appear to not work. The layout is also messed up if specifying true to add to rootView on inflate.Ostrogoth
S
22

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);
Shepp answered 14/1, 2014 at 11:7 Comment(0)
A
9

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);
Adios answered 3/2, 2013 at 1:59 Comment(1)
Yes, my view is nested with <FrameLayout> <ImageView /> <TextViews> </FrameLayout>Mariejeanne
M
0

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
    }
  }
Mosby answered 3/12, 2020 at 5:41 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.