Skip to content

Magellan 1.x Working With The Action Bar

Ryan Moelter edited this page Jul 18, 2021 · 1 revision

If you want to customize the Action Bar, Magellan provides some functionality to do this.

It's worth noting that out of the box, you do not need to customize the action bar when using Magellan. If your app theme extends an AppCompat theme with an action bar, you will have an action bar whose title can be set by each Screen, and it will work fine.

If, however, you do want to customize the action bar, Magellan provides an ActionBarConfig class containing the information to do so. The ActionBarConfig class allows you to set the following details:

  • whether the action bar should be shown
  • whether changes to the action bar should be animated
  • the color of the action bar

Custom Action Bar Setup Steps

When you make the decision to control the action bar yourself, the following steps will help you get set up. Many of these steps are from the Google Android Developer site for setting up the App Bar. Also, you can see how this is done by looking at the code for the advanced sample app.

1. Ensure your Activity extends AppCompatActivity

public class MainActivity extends AppCompatActivity {/.../}

2. Add a Toolbar to your Activity xml

You will want to add a Toolbar on top of the container for your Screens (and wrap it all in an appropriate ViewGroup. Your activity_main.xml will likely resemble this:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
    <!-- Appropriate Container attributes -->
    >

  <android.support.v7.widget.Toolbar
      android:id="@+id/toolbar"
      android:layout_width="match_parent"
      android:layout_height="?attr/actionBarSize"
      android:background="?attr/colorPrimary"
      app:titleTextColor="@android:color/white"
      app:navigationIcon="@mipmap/magellan_icon"
      android:theme="@style/ActionBar"
      />

  <com.wealthfront.magellan.ScreenContainer
      android:id="@+id/magellan_container"
      android:layout_width="match_parent"
      android:layout_height="match_parent"
      />

</LinearLayout>

3. Set the Toolbar as your support action bar in your Activity

public class MainActivity extends AppCompatActivity {

    Toolbar toolbar;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        // onCreate code here
        toolbar = ButterKnife.findById(this, R.id.toolbar);
        setSupportActionBar(toolbar);
    }
}

4. Update your action bar when navigation events occur

Magellan provides an interface for listening to navigation events, NavigationListener. This NavigationListener interface contains a single method (onNavigate) that passes the ActionBarConfig for the Screen that is being shown. You use the ActionBarConfig from this method to update the action bar in your Activity.

public class MainActivity extends AppCompatActivity implements NavigationListener {

    /**
    Main Activity code here...
    */

    @Override
    public void onNavigate(ActionBarConfig actionBarConfig) {
        // Update action bar config based on new Screen settings
        setActionBarColor(actionBarConfig.colorRes());
        if (actionBarConfig.visible()) {
            showActionBar(actionBarConfig.animated());
        } else {
            hideActionBar(actionBarConfig.animated());
        }
        // Need to manually update logo
        if (navigator.atRoot()) {
            toolbar.setNavigationIcon(R.drawable.action_bar_icon);
        } else {
            toolbar.setNavigationIcon(R.drawable.back_arrow);
        }
    }
}

5. Override action bar config methods in each Screen

Each Screen is responsible for setting the configuration by overriding the following methods:

// This method must be overriden by each Screen otherwise
// your app will crash when navigating to that Screen due 
// to an invalid action bar color resource id
@ColorRes
protected int getActionBarColorRes() {} // Defaults to 0

protected boolean shouldShowActionBar() {} // Defaults to true

protected boolean shouldAnimateActionBar() {} // Defaults to true

Optional (but useful): Adding a menu

If you want to add a menu, here's a way to do that.

Inflate menu in onCreateOptionsMenu and pass it to the Navigator

Just like if you wanted an options menu in a regular, non-Magellan Activity, you first inflate your menu in your Activity's onCreateOptionsMenu method. But once you do that, you will want to let Magellan's Navigator know that you've created this menu. By telling the Navigator about this menu, the Navigator will take care of hiding munu items that are not needed by the Screen being shown. Ultimately, your onCreateOptionsMenu will likely look something like this:

@Override
public boolean onCreateOptionsMenu(Menu menu) {
    getMenuInflater().inflate(R.menu.menu_main, menu);
    navigator.onCreateOptionsMenu(menu); // the important part
    return true;
}

Handle menu item clicks in your Activity

As of now, handling menu item clicks is done by the main Activity class, not individual Screens (though this could change in future releases). This is because we've found most menu items have a consistent behavior across all screens in your app. So you need to override the onOptionsItemSelected method in your Activity to listen for and respond to menu item click events. It should look something like this (taken from the advanced sample):

@Override
  public boolean onOptionsItemSelected(MenuItem item) {
    switch (item.getItemId()) {
      case android.R.id.home:
        return navigator.handleBack();
      case R.id.animateActionBar:
        navigator.goTo(new ActionBarHiddenScreen());
        return true;
      default:
        return super.onOptionsItemSelected(item);
    }
  }

Have each Screen define menu items to show

It is the responsibility of the Screen to show the menu items it wants users to be able to use. By default, the Navigator will hide every menu item when you navigate to a new Screen. To show a menu item on a given Screen, override the Screen's onUpdateMenu method. An example:

@Override
protected void onUpdateMenu(Menu menu) {
    menu.findItem(R.id.animateActionBar).setVisible(true);
}