In our app we are trying to dynamically add fragments to a GridLayout. The empty grid layout is defined in XML as is the layout for the fragment. At run time we examine some data and from that determine the number of fragments to add to the layout as well as which layout to use for each fragment. When we have the fragment assign a size to its generated view it all works, however if we specify the size in the layout file for the fragment nothing shows up in the grid layout. Obviously we could simply specify the size when we create the view but we would prefer to do it in the xml layouts for the fragments because that would allow us to take advantage of Android's built in system for selecting the correct layouts for each device.
I am using support library fragments. I am NOT using support library GridLayout if that makes a difference
The relevant code and xml follows:
The GridLayout XML:
<?xml version="1.0" encoding="utf-8"?>
<merge xmlns:android="http://schemas.android.com/apk/res/android">
<ScrollView
android:id="@+id/grid_scroll"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_above="@+id/bottom_fragment"
android:layout_alignParentLeft="true"
android:layout_alignParentTop="true"
android:layout_marginRight="8dp"
android:layout_marginTop="?android:attr/actionBarSize"
android:overScrollMode="ifContentScrolls" >
<GridLayout
android:id="@+id/grid"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:alignmentMode="alignMargins"
android:animateLayoutChanges="true"
android:columnCount="3"
android:columnOrderPreserved="true"
android:orientation="horizontal"
android:overScrollMode="ifContentScrolls"
android:rowOrderPreserved="true" >
</GridLayout>
</ScrollView>
</merge>
An Example of the Fragment XML
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="200dp"
android:layout_height="100dp"
android:alpha="1" >
<Button
android:id="@+id/button1"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:alpha="1.0" />
</RelativeLayout>
The Fragment onCreateView() Method
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
super.onCreateView(inflater, container, savedInstanceState);
View view;
GridLayout.Spec rowSpec = GridLayout.spec(mRowStart, mRowSpan);
GridLayout.Spec columnSpec;
GridLayout.LayoutParams childParams;
if (large) {;
view = inflater.inflate(R.layout.my_place_large, container, false);
columnSpec = GridLayout.spec(mColumnStart, 2);
childParams = new GridLayout.LayoutParams(rowSpec, columnSpec);
//childParams.width = 200; //If I do this everything works regardless of the layout size
} else {
view = inflater.inflate(R.layout.my_place_small, container, false);
columnSpec = GridLayout.spec(mColumnStart, 1);
childParams = new GridLayout.LayoutParams(rowSpec, columnSpec);
//childParams.width = 100; //If I do this everything works regardless of the layout size
}
childParams.setMargins(0, 0, 0, 0);
//childParams.height = 100; //If I do this everything works regardless of the layout size
view.setLayoutParams(childParams);
view.setId(ID);
return view;
}
To Add Fragments to the Layout
private void populateGrid() {
RelativeLayout gridParent = (RelativeLayout) mParentActivity.findViewById(R.id.locations);
mLocationsGrid = (GridLayout) gridParent.findViewById(R.id.grid);
nColumns = mLocationsGrid.getColumnCount();
mAdapter = new MyAdapter(mContext, this, mResolver); //This is how I keep track of the various fragments depending on my app's state
int nCards = mAdapter.getNumberOfCards();
FragmentManager fragmentManager = mParentActivity.getSupportFragmentManager();
FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();
for (int i = 0; i < nCards; ++i) {
fragmentTransaction.add(mLocationsGrid.getId(), mAdapter.getFragmentAtIndex(i), String.valueOf(i));
}
fragmentTransaction.commit();
mPopulated = true;
}
I think that should cover it. Just to reiterate, if I uncomment the lines which explicitly set the dimension in onCreateView(), they show up properly in GridLayout so I know everything that keeps track of the fragments and such works, as does the fragment transaction. The issue comes when I try and specify the size in the fragment's xml in which case I get a blank screen.
You thoughts, suggestions and musings are appreciated. Thanks, Jared
To declaratively add a fragment to your activity layout's XML, use a FragmentContainerView element. The android:name attribute specifies the class name of the Fragment to instantiate.
onCreateView() The system calls this method when Android needs the layout for the fragment. The Fragment class and Fragment Transaction class allow you to add, remove and replace fragments in the layout of your activity. Fragments can be dynamically modified by the transaction.
Accessing in a Fragment Inside a fragment, you can get a reference to the FragmentManager that manages the fragment's children through getChildFragmentManager() . If you need to access its host FragmentManager , you can use getParentFragmentManager() .
FragmentContainerView is a customized Layout designed specifically for Fragments. It extends FrameLayout , so it can reliably handle Fragment Transactions, and it also has additional features to coordinate with fragment behavior.
This is coming very late, but in the off chance this may still be of use. The problem is that you are overriding the XML layout parameters when you dynamically set the new LayoutParams. IE, when you do:
view.setLayoutParams(childParams);
This will erase the XMLs original height and width setting. Just because you are leaving the childParams width/height blank in code doesn't mean a value is not set. In a GridLayout's case, they are set to undefined
.
The fix would be to first save the View's existing LayoutParam's height/width and use that when creating the new LayoutParam dynamically. Example:
if (large) {;
view = inflater.inflate(R.layout.my_place_large, container, false);
ViewGroup.LayoutParams oldParams = view.getLayoutParams();
columnSpec = GridLayout.spec(mColumnStart, 2);
childParams = new GridLayout.LayoutParams(rowSpec, columnSpec);
childParams.width = oldParams.width;
}
That will allow you to keep the width/height in XML while applying the row/col specs in code.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With