Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Dynamically adding fragments with xml layout to GridLayout is not workng

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

like image 764
Jared Avatar asked Nov 15 '12 03:11

Jared


People also ask

What object is used to add a fragment to a layout?

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.

Is used to perform add/remove or replace fragment dynamically in your activity?

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.

How do I get FragmentManager in fragment?

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() .

What is FragmentContainerView?

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.


1 Answers

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.

like image 141
Jay Soyer Avatar answered Sep 22 '22 18:09

Jay Soyer