I am trying to spawn some XML view for each instance of POJO data objects in a list, similar to how a ListView would do it, but it’s not a ListView
actually, but an empty LinearLayout instead, which is inside a ScrollView
below other Fragment
‘s content.
This is the item.xml
file I want to inflate for each element of the list:
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="wrap_content" android:orientation="vertical" > <TextView android:id="@+id/item_label" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginStart="8dp" android:layout_marginLeft="8dp" android:layout_marginTop="0dp" android:text="ITEM_LABEL" android:textSize="16sp" /> <TextView android:id="@+id/item_text1" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginStart="8dp" android:layout_marginLeft="8dp" android:layout_marginTop="4dp" android:text="ITEM_TEXT_1" android:textSize="14sp" /> <TextView android:id="@+id/item_text2" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginStart="8dp" android:layout_marginLeft="8dp" android:layout_marginTop="4dp" android:text="ITEM_TEXT_2" android:textSize="14sp" /> </LinearLayout>
…and this is the way I am trying to inflate it in the Fragment
Java class:
public class MyFragment extends Fragment { // we skip the "boilerplate"... // [...] @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { // Inflate the layout for this fragment View view = inflater.inflate(R.layout.my_fragment, container, false); // XXX I use LiveData<> with Room to retrieve // rows from DB inside POJO objects LiveData<List<MyItem>> items_list = itemsViewModel.getItemsByParentId(some_id); // The "parent" is not relevant, let's just // focus on the List LinearLayout items_list_layout = view.findViewById(R.id.items_list_layout); items_list.observe(getActivity(), new Observer<List<MyItem>>() { @Override public void onChanged(List<MyItem> items) { // Just in case, (maybe I'm wrong but) I think otherwise // previous inflated objects remain on loading this same // fragment for another parent objs_list_layout.removeAllViews() for (MyItem item : items) { // XXX Here I inflate item.xml as a LinearLayout LinearLayout obj_item = (LinearLayout) View.inflate(view.getContext(), R.layout.item, items_list_layout); // XXX ... and try to change it's TextView children TextView item_label = obj_item.findViewById(R.id.item_label); item_label.setText(item.item_label); TextView item_text1 = obj_item.findViewById(R.id.item_text1); item_text1.setText(item.item_text1); TextView item_text2 = obj_item.findViewById(R.id.item_text2); item_text2.setText(item.item_text2); } } }); } }
This works well when the method getItemsByParentId
only return a List
with one only MyItem
instance. But when the query returns more than one Item, it works unexpectedly wrong:
- The first inflated
item.xml
element (or the one shown first, on top) has itsTextViews
modificated as expected, but for the last item in the list. - The rest of “inflated elements” have not been changed (it shows just ITEM_LABEL, ITEM_TEXT1 and ITEM_TEXT2 hardcoded strings as they are in the template XML file).
- However, it inflates the XML template
items.size()
times as I planned.
Actually, the objective is that each “inflated item.xml
” is edited with attributes of each corresponding Item. Just like a ListView would do, but without using ListView at all, because the goal is, actually, bloating an existing ScrollView
(the main container in the fragment) that shows other different Views outside of the “LinearLayout” dedicated to generate this “list”. How can I make it work without these errors?
Advertisement
Answer
View.inflate
imho is a not the clearest method ) it returns the root View of the inflated hierarchy. If root was supplied, this is the root View; otherwise it is the root of the inflated XML file.
So obj_item is not an item view. It is an items_list_layout view. Inside it you find R.id.item_label
in first item view and set it. Other item views are not initialized because findViewById returns first item it found.
Change this part:
LinearLayout obj_item = (LinearLayout) View.inflate(view.getContext(), R.layout.item, items_list_layout);
to
LinearLayout obj_item = LayoutInflator.from(view.getContext()).inflate(R.layout.item, items_list_layout, false);
I prefer to add child views explicitly to make code more readable. So and add this code to add item view to parent layout:
items_list_layout.addView(obj_item)