Navigating between fragments

Fragments can be navigated through and back, like activities. Sometimes we have a layout that will be displayed when a user selects an option, and we want the back navigation to be as seamless as pressing the back button.

How to do it...

When it comes to navigation with fragments, we do not insert the fragments into the layout. Rather, we use an empty container layout. Then, at runtime, we insert the correct fragment:

  1. First, we are going to add a new layout for portrait view. Landscape will be the original two-pane layout, and the new portrait view will have the single pane, but with swapping (Resources/layout-port/Main.axml):
    <?xml version="1.0" encoding="utf-8"?>
    <FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
      android:id="@+id/fragmentContainer"
      android:layout_width="match_parent"
      android:layout_height="match_parent"/>
  2. Next, we need to initialize FrameLayout by loading the first fragment, MenuFragment, at startup. If FrameLayout is obtainable, then we are in portrait mode, so we load the menu fragment:
    protected override void OnCreate(Bundle bundle) {
      //...
      FrameLayout container = FindViewById<FrameLayout>(
        Resource.Id.fragmentContainer);
      if (container != null) {
        Fragment menu = SupportFragmentManager.FindFragmentById(
            Resource.Id.menu);
        if (bundle == null || menu == null) {
          menu = new MenuFragment();
          SupportFragmentManager
            .BeginTransaction()
            .Add(Resource.Id.fragmentContainer, menu)
            .Commit();
        }
      }
    }
  3. Now we need to handle the menu selections and swap the menu out with the content. If we are in portrait mode, we use a transaction to show the content fragment with arguments. Otherwise, we just find the content fragment and update it:
    public void OnMenuSelected(string text) {
      FrameLayout container = FindViewById<FrameLayout>(
        Resource.Id.fragmentContainer);
    
      if (container != null) {
        Bundle args = new Bundle();
        args.PutString(ContentFragment.ArgumentsKey, text); 
        ContentFragment content = new ContentFragment();
        content.Arguments = args;
    
        SupportFragmentManager
          .BeginTransaction()
          .Replace(Resource.Id.fragmentContainer, content)
          .AddToBackStack(null)
          .Commit();
      }
      else {
        ContentFragment content = SupportFragmentManager.FindFragmentById(
            Resource.Id.content) as ContentFragment;
        content.Update(text);
      }
    }
  4. In order for the fragment to receive the updates from the activity, we need to read the arguments that were passed in from the main activity. This we do in the OnStart() method of the content fragment as the view will already be constructed, allowing us to update it. Let's take a look at the following code snippet:
    if (Arguments != null) {
      currentText = Arguments.GetString(ArgumentsKey);
    }

How it works...

When creating dynamic layouts, we can sometimes just design several layout files, each with variations based on the target screen configuration or device. However, greater flexibility can be achieved if we use fragments and switch them around at runtime. Fragments can be used to create dynamic and flexible interfaces and allow reuse of the layouts as well as the logic behind it.

Because we are going to load, unload, and replace fragments at runtime, we make use of FragmentManager. This type provides access to the FragmentTransaction API, which encapsulates changes to fragments—such as add, remove, and replace—into a single, reversible operation.

Note

In order to remove a fragment at runtime, it has to be created at runtime. If it was inserted in the XML layout, it can't be removed.

Using this API, we can perform actions such as add or replace as well as assign transitions with SetTransition and then apply the transaction with Commit. These changes can be added to the back stack, using AddToBackStack, so that we can "roll back" to the previous fragment when the user taps the Back button.

Fragment operations require a view that acts as a container for the fragments. Each Add, Replace, and Remove operation in a transaction is passed the ID of the container as a parameter along with the fragment.

When initializing the fragments in the OnCreate() method of an activity, we need to check to see if the fragments don't already exist. Android will restore the state automatically, including the fragments and fragment back stack, so we only have to set up the fragments initially.

If a fragment is removed without it's being added to the back stack, it is destroyed and is not available when going back. If AddToBackStack is called, the current fragment is stopped but then resumed when navigating back.

Note

Fragment transactions have to be added to the back stack in order to be able to pop back to it from a transaction.

In order to pass values using fragment navigation, we use the Arguments property, which is a Bundle type. This allows us to pass values in key-value pairs to the fragment. Inside the fragment, we can then query the Arguments property to read the values.

See also

  • Creating and using fragments
..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset