Customize toolbar menus on Android

You can modify Nutrient’s menus by adding new actions or removing existing actions. For code examples, see CustomActionsExample (Java) or CustomActionsKotlinExample (Kotlin) from our example Catalog.

Modifying the action bar

If you are using the PdfActivity or a custom subclass of this activity, Nutrient will automatically show toolbar actions based on the loaded configuration. Nutrient uses the default support Toolbar widget together with a dynamically populated Menu.

Default actions: Annotation editing, outline, searching, sharing, thumbnails, and the overflow menu.

Adding custom actions

To add custom actions to existing actions, you need to use a custom activity class and override #onCreateOptionsMenu or #onPrepareOptionsMenu, depending on your needs. The calls to these methods are made the same way they are by default on the Android system. #onCreateOptionsMenu is called the first time the menu is created, and #onPrepareOptionsMenu is called whenever the menu is changed or invalidated. To alter the list of items that will be displayed in the first place, you need to override #onGenerateMenuItemIds and return a final list of menu item IDs that will be displayed, like so:

class CustomActivity : PdfActivity() {
    /**
     * Override this method to get the list of menu item IDs, as they'll be ordered by default.
     * You can add your own menu item IDs that you can later edit in `[.onCreateOptionsMenu]`
     * or `[.onPrepareOptionsMenu]`.
     */
    override fun onGenerateMenuItemIds(menuItems: MutableList<Int>): List<Int> {
        // For example, let's say we want to add custom menu items after the outline button.
        // First, we get an index of outline buttons (all default button IDs can be retrieved
        // via `MENU_OPTION_*` variables defined in the `PdfActivity`).
        val indexOfOutlineButton = menuItems.indexOf(PdfActivity.MENU_OPTION_OUTLINE)

        // Add a custom item after the outline button.
        menuItems.addAll(indexOfOutlineButton + 1, R.id.custom_action1)

        // Return the new menu items order.
        return menuItems
    }

    override fun onCreateOptionsMenu(menu: Menu): Boolean {
        // This will populate the menu with items ordered as specified in `onGenerateMenuItemIds()`.
        super.onCreateOptionsMenu(menu)

        // Edit the custom button.
        val customMenuItem = menu.findItem(R.id.custom_action1)
        customMenuItem.title = "Menu Item 1"
        customMenuItem.setIcon(R.drawable.ic_arrow_left)

        // Let's say we want the icon to be tinted the same color as the default ones. We can read the color
        // from the theme, or we can specify the same color we have in the theme. Reading from the theme is a bit
        // more complex, but this a better way to do it, so here's how:
        val a = theme.obtainStyledAttributes(
                null,
                R.styleable.pspdf__ActionBarIcons,
                R.attr.pspdf__actionBarIconsStyle,
                R.style.PSPDFKit_ActionBarIcons
        )
        val mainToolbarIconsColor = a.getColor(R.styleable.pspdf__ActionBarIcons_pspdf__iconsColor, ContextCompat.getColor(this, R.color.white))
        a.recycle()

        // Tinting custom menu drawable.
        val customIcon = customMenuItem.icon
        DrawableCompat.setTint(customIcon, mainToolbarIconsColor)
        customMenuItem.icon = customIcon

        // All our menu items are marked as `SHOW_AS_ALWAYS`. If you want to, for example,
        // just show the first four items and send the others to the overflow, you can simply do:
        for (i in 0 until menu.size()) {
            menu.getItem(i).setShowAsAction(if (i < 4) MenuItem.SHOW_AS_ACTION_ALWAYS else MenuItem.SHOW_AS_ACTION_NEVER)
        }

        return true
    }

    override fun onPrepareOptionsMenu(menu: Menu): Boolean {
        // Here, you can edit your items when the menu is being invalidated.
        // To invalidate the menu, call `supportInvalidateOptionsMenu();`
        return super.onPrepareOptionsMenu(menu)
    }
}
public class CustomActivity extends PdfActivity {

    /**
     * Override this method to get the list of menu item IDs, as they'll be ordered by default.
     * You can add your own menu item IDs that you can later edit in `{@link #onCreateOptionsMenu(Menu)}`
     * or `{@link #onPrepareOptionsMenu(Menu)}`.
     */
    @NonNull
    @Override
    public List<Integer> onGenerateMenuItemIds(@NonNull List<Integer> menuItems) {
        // For example let's say we want to add custom menu items after the outline button.
        // First, we get an index of outline buttons (all default button IDs can be retrieved
        // via `MENU_OPTION_*` variables defined in the `PdfActivity`.
        int indexOfOutlineButton = menuItems.indexOf(MENU_OPTION_OUTLINE);

        // Add a custom item after the outline button.
        menuItems.add(indexOfOutlineButton + 1, R.id.custom_action1);

        // Return the new menu items order.
        return menuItems;
    }

    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        // This will populate the menu with items ordered as specified in `onGenerateMenuItemIds()`.
        super.onCreateOptionsMenu(menu);

        // Edit the custom button.
        MenuItem customMenuItem = menu.findItem(R.id.custom_action1);
        customMenuItem.setTitle("Menu Item 1");
        customMenuItem.setIcon(R.drawable.ic_arrow_left);

        // Let's say we want the icon to be tinted the same color as the default ones. We can read the color
        // from the theme, or we can specify the same color we have in the theme. Reading from the theme is a bit
        // more complex, but this a better way to do it, so here's how:
        final TypedArray a = getTheme().obtainStyledAttributes(
                null,
                R.styleable.pspdf__ActionBarIcons,
                R.attr.pspdf__actionBarIconsStyle,
                R.style.PSPDFKit_ActionBarIcons
        );
        int mainToolbarIconsColor = a.getColor(R.styleable.pspdf__ActionBarIcons_pspdf__iconsColor, ContextCompat.getColor(this, R.color.white));
        a.recycle();

        // Tinting custom menu drawable.
        Drawable customIcon = customMenuItem.getIcon();
        DrawableCompat.setTint(customIcon, mainToolbarIconsColor);
        customMenuItem.setIcon(customIcon);

        // All our menu items are marked as `SHOW_AS_ALWAYS`. If you want to, for example,
        // just show the first four items and send the others to the overflow, you can simply do:
        for (int i = 0; i < menu.size(); i++) {
            menu.getItem(i).setShowAsAction(i < 4 ? MenuItem.SHOW_AS_ACTION_ALWAYS : MenuItem.SHOW_AS_ACTION_NEVER);
        }

        return true;
    }

    @Override
    public boolean onPrepareOptionsMenu(Menu menu) {
        // Here, you can edit your items when the menu is being invalidated.
        // To invalidate the menu, call `supportInvalidateOptionsMenu();`
        return super.onPrepareOptionsMenu(menu);
    }
}

Specifying the position for custom actions

To add a custom action at a specific position, your activity has to override the #onGenerateMenuItemIds method. From there, you can control at which position the custom item should be inserted. Below is an example of how to insert a custom menu item directly after the outline button:

class CustomActivity : PdfActivity() {
    override fun onGenerateMenuItemIds(menuItems: MutableList<Int>): List<Int> {
        // First, we get an index of the outline button.
        val indexOfOutlineButton = menuItems.indexOf(PdfActivity.MENU_OPTION_OUTLINE)

        // Add items after the outline button.
        menuItems.add(
            indexOfOutlineButton + 1,
            R.id.custom_action // Your custom action ID.
        )

        // Return the new order for menu items.
        return menuItems
    }
}
public class CustomActivity extends PdfActivity {
    @Override
    public List<Integer> onGenerateMenuItemIds(@NonNull List<Integer> menuItems) {
        // First, we get an index of the outline button.
        int indexOfOutlineButton = menuItems.indexOf(MENU_OPTION_OUTLINE);

        // Add items after the outline button.
        menuItems.add(
            indexOfOutlineButton + 1,
            R.id.custom_action // Your custom action ID.
        );

        // Return the new order for menu items.
        return menuItems;
    }
}

Default menu option IDs

Here are the IDs for all the menu options from the main action bar. You can reference them using PdfActivity:

ID Default action
MENU_OPTION_EDIT_ANNOTATIONS Enters annotation editing mode.
MENU_OPTION_OUTLINE Shows PdfOutlineView with bookmarks, document info, an outline, and the annotation list.
MENU_OPTION_SEARCH Enters the search document contents mode.
MENU_OPTION_SETTINGS Shows the document settings menu.
MENU_OPTION_SHARE Shows the share dialog.
MENU_OPTION_THUMBNAIL_GRID Enters document editor mode.

Removing default actions

To remove default actions (search, share, document settings, etc.), you need to override the #onGenerateMenuItemIds method and remove the corresponding IDs from the list:

class CustomActivity : PdfActivity() {
    override fun onGenerateMenuItemIds(menuItems: MutableList<Int>): List<Int> {
        // Take the default menu item IDs and remove the outlined items.
        menuItems.remove(PdfActivity.MENU_OPTION_OUTLINE)

        // Return the new order for the menu items.
        return menuItems
    }
}
public class CustomActivity extends PdfActivity {
    @Override
    public List<Integer> onGenerateMenuItemIds(@NonNull List<Integer> menuItems) {
        // Take the default menu item IDs and remove the outlined items.
        menuItems.remove(PdfActivity.MENU_OPTION_OUTLINE);

        // Return the new order for the menu items.
        return menuItems;
    }
}

Keep in mind that manipulating menu items will not affect certain initialization steps performed for the actions they represent, and it will still be possible to trigger those actions programmatically. For example, removing the search action as described above will still initialize SearchView under the hood, and it can still be invoked programmatically.

If you want to not only remove a certain action from the menu but also completely disable the functionality it represents, use one of the following PdfActivityConfiguration options:

Configuration option Result
disableAnnotationEditing() Disables annotation editing and removes all related UI elements.
disableOutline() Disables the outline and removes all related UI elements.
disableSearch() Disables search functionality and removes all related UI elements.
hideSettingsMenu() Removes the settings menu.
setEnabledShareFeatures(ShareFeatures.none()) Disables share functionality and removes all related UI elements.
hideThumbnailGrid() Disables the thumbnail grid and removes all related UI elements.

Customizing the document settings menu

You can control which items will be shown in a document settings menu (see the default version below).

To specify which items should be shown in this menu, use PdfActivityConfiguration.Builder#setSettingsMenuItems. For example, the following code will result in the settings menu showing only the page transition, page layout, and document theme:

configuration.setSettingsMenuItems(EnumSet.of(
    SettingsMenuItemType.THEME,
    SettingsMenuItemType.PAGE_LAYOUT,
    SettingsMenuItemType.PAGE_TRANSITION
    )
)
configuration.setSettingsMenuItems(EnumSet.of(
    SettingsMenuItemType.THEME,
    SettingsMenuItemType.PAGE_LAYOUT,
    SettingsMenuItemType.PAGE_TRANSITION
    )
)

The result will look like the following.

To exclude the settings menu completely, you can use PdfActivityConfiguration.Builder#hideSettingsMenu:

configuration.hideSettingsMenu()
configuration.hideSettingsMenu()

Adding an action to the share menu

By overriding the #onPrepareOptionsMenu method, you can also add actions to submenus — for example, to the share menu. To do so, first fetch the menu item via its ID, PdfActivity.MENU_OPTION_SHARE, and then add your action to its submenu:

val shareMenu = menu.findItem(PdfActivity.MENU_OPTION_SHARE).subMenu
shareMenu.add(0, R.id.my_custom_action, 0, "My custom share action")
final SubMenu shareMenu = menu.findItem(PdfActivity.MENU_OPTION_SHARE).getSubMenu();
shareMenu.add(0, R.id.my_custom_action, 0, "My custom share action");