Add a fragment as ListView header
Asked Answered
P

3

5

I'm targeting an android app to API 15 and minimum 8. So I use support library to manage fragments. I have a set of fragments that I use in several parts of the app.

Now, in an activity I have a ListView in the layout:

<ListView xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:id="@+id/listOfEvents"
    android:layout_width="match_parent" android:layout_height="match_parent">
</ListView>

I would like to add a fragment of mine in the ListView header. I tried this:

    @Override
public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.event_open);

    listOfEvents = (ListView) findViewById(R.id.listOfEvents);

            Fragment fragment = new SortingStandardFragment();
            getSupportFragmentManager()
              .beginTransaction()
                  .add(fragment, null)
              .commit();

            View fragmentView = fragment.getView(); // problem: fragment is null!
            listOfEvents.addHeaderView(fragmentView);
    }

but i get an error since fragment.getView() returns null (api reference docs say that I have to put a GroupView Id in the add call, but where should I put the GroupView in the layout? Is there another way to hit the mark?

Prasad answered 27/9, 2012 at 21:51 Comment(1)
I'm not sure this can work this way, but the fragment idea is creating a framelayout setting an id (you can make id by adding id name in resources), add as header and then make a transaction replacing that id with the fragmentLaky
P
14

I solved this by creating a new layout containing just the fragment I need in the list header:

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <fragment
        android:id="@+id/myFragmentEmbedded"
        android:name=".SortingStandardFragment"
        android:layout_width="match_parent"
        android:layout_height="wrap_content" />

</LinearLayout>

and in the activity code:

LayoutInflater inflater = getLayoutInflater();
header = inflater.inflate(R.layout.myLayout, null);
listOfEvents.addHeaderView(header);

SortingStandardFragmenttitleFragment = (SortingStandardFragment) 
     getSupportFragmentManager()
          .findFragmentById(R.id.myFragmentEmbedded);
Prasad answered 30/9, 2012 at 21:22 Comment(0)
T
4

I wanted a version without having to resort to yet another xml file, so here it goes:

Fragment fragment = ...
FrameLayout v = new FrameLayout(getActivity());
v.setId(42);
listView.addHeaderView(v, null, false);
FragmentManager fm = getActivity().getSupportFragmentManager();
fm.beginTransaction().add(v.getId(), fragment).commit();
Trioecious answered 5/2, 2014 at 20:10 Comment(2)
it is best to declare the id in the ids.xml file, though, to make sure there is no risk of overlapping ids.Trioecious
if you add header container to ListView not in onCreate (supposably after request), you app crash in onBackPressed() because listview destroy child(you header container) after stop - fragmentmanager not inject you fragment into containerMeltwater
O
1

In case anyone is curious why his first attempt failed:

  • lifecycle events are posted to the UI thread
  • Fragment.onCreateView is a lifecycle event
  • Activity.onCreate is a lifecycle event
  • .getView() returns the created view in Fragment.onCreateView
  • commit post a lifecycle event

Conclusion: the result of commit is visible from the next loop which is after onCreate returned.

One could try forcing commit to be immediate with getSupportFragmentManager().executePendingTransactions(), after reading the documentation on it.

Oxonian answered 13/11, 2014 at 16:40 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.