Customizing Toolbars in Our Android PDF Viewer
PSPDFKit comes with a flexible toolbar system that provides basic action bar functionality, as well as powerful editing features.
This guide covers contextual toolbar customization. For customizing the main toolbar (referred to as a menu), see our Customizing Menus guide.
Styling the Toolbar
By default, PSPDFKit will apply default styles to all of its toolbars. A large set of style attributes allows you to modify the appearance of toolbars according to your app’s look. Check out the styling guide, which gives an overview of all available style attributes.
Change the Grouping of Toolbar Items
Each toolbar contains ContextualToolbarMenuItem
s representing toolbar elements/items.
The rules of how menu items in each toolbar are grouped are defined in classes extending PresetMenuItemGroupingRule
, which you can set through setMenuItemGroupingRule()
called on the specific toolbar. What you want to do is override PresetMenuItemGroupingRule#getGroupPreset()
, returning a different structure depending on the given toolbar capacity.
MenuItem
represents a structure, using IDs for identification, of how ContextualToolbarMenuItem
s with those IDs would be positioned/grouped. For more details on the implementation, check out CustomToolbarIconGroupingExample
in the Catalog app.
For example, let’s define a custom grouping of menu items for AnnotationCreationToolbar
, but with our own added custom item:
class MyCustomGrouping(context: Context) : PresetMenuItemGroupingRule(context) { override fun getGroupPreset(capacity: Int, itemsCount: Int): List<MenuItem> { // The capacity shouldn't be less than 4. If that is the case, return an empty list. if (capacity < ContextualToolbar.MIN_TOOLBAR_CAPACITY) return emptyList<MenuItem>() return if (capacity <= 7) FOUR_ITEMS_GROUPING else SEVEN_ITEMS_GROUPING } /** Annotation toolbar grouping with 4 elements. */ private val FOUR_ITEMS_GROUPING = listOf( MenuItem(R.id.pspdf_menu_custom), MenuItem(com.pspdfkit.R.id.pspdf__annotation_creation_toolbar_group_markup, intArrayOf( com.pspdfkit.R.id.pspdf__annotation_creation_toolbar_item_highlight, com.pspdfkit.R.id.pspdf__annotation_creation_toolbar_item_squiggly, com.pspdfkit.R.id.pspdf__annotation_creation_toolbar_item_strikeout, com.pspdfkit.R.id.pspdf__annotation_creation_toolbar_item_underline)) MenuItem(com.pspdfkit.R.id.pspdf__annotation_creation_toolbar_item_picker), MenuItem(com.pspdfkit.R.id.pspdf__annotation_creation_toolbar_item_image) ) /** Annotation toolbar grouping with 7 elements. */ private val SEVEN_ITEMS_GROUPING = listOf( MenuItem(R.id.pspdf_menu_custom), MenuItem(com.pspdfkit.R.id.pspdf__annotation_creation_toolbar_item_highlight), MenuItem(com.pspdfkit.R.id.pspdf__annotation_creation_toolbar_item_squiggly), MenuItem(com.pspdfkit.R.id.pspdf__annotation_creation_toolbar_item_strikeout), MenuItem(com.pspdfkit.R.id.pspdf__annotation_creation_toolbar_item_underline), MenuItem(com.pspdfkit.R.id.pspdf__annotation_creation_toolbar_item_picker), MenuItem(com.pspdfkit.R.id.pspdf__annotation_creation_toolbar_item_image) ) }
public class MyCustomGrouping extends PresetMenuItemGroupingRule { public CustomAnnotationCreationToolbarGroupingRule(@NonNull Context context) { super(context); } @Override public List<MenuItem> getGroupPreset(@IntRange(from = ContextualToolbar.MIN_TOOLBAR_CAPACITY) int capacity, int itemsCount) { // The capacity shouldn't be less than 4. If that is the case, return an empty list. if (capacity < ContextualToolbar.MIN_TOOLBAR_CAPACITY) return new ArrayList<>(0); return (capacity <= 7) ? FOUR_ITEMS_GROUPING : SEVEN_ITEMS_GROUPING; } /** Annotation toolbar grouping with 4 elements. */ private static final List<MenuItem> FOUR_ITEMS_GROUPING = new ArrayList<>(4); static { // Make sure our custom item is included. FOUR_ITEMS_GROUPING.add(new MenuItem(R.id.pspdf_menu_custom)); FOUR_ITEMS_GROUPING.add(new MenuItem(com.pspdfkit.R.id.pspdf__annotation_creation_toolbar_group_markup, new int[]{ com.pspdfkit.R.id.pspdf__annotation_creation_toolbar_item_highlight, com.pspdfkit.R.id.pspdf__annotation_creation_toolbar_item_squiggly, com.pspdfkit.R.id.pspdf__annotation_creation_toolbar_item_strikeout, com.pspdfkit.R.id.pspdf__annotation_creation_toolbar_item_underline})); FOUR_ITEMS_GROUPING.add(new MenuItem(com.pspdfkit.R.id.pspdf__annotation_creation_toolbar_item_picker)); FOUR_ITEMS_GROUPING.add(new MenuItem(com.pspdfkit.R.id.pspdf__annotation_creation_toolbar_item_image)); } /** Annotation toolbar grouping with 7 elements. */ private static final List<MenuItem> SEVEN_ITEMS_GROUPING = new ArrayList<>(7); static { // Make sure our custom item is included. SEVEN_ITEMS_GROUPING.add(new MenuItem(R.id.pspdf_menu_custom)); SEVEN_ITEMS_GROUPING.add(new MenuItem(com.pspdfkit.R.id.pspdf__annotation_creation_toolbar_item_highlight)); SEVEN_ITEMS_GROUPING.add(new MenuItem(com.pspdfkit.R.id.pspdf__annotation_creation_toolbar_item_squiggly)); SEVEN_ITEMS_GROUPING.add(new MenuItem(com.pspdfkit.R.id.pspdf__annotation_creation_toolbar_item_strikeout)); SEVEN_ITEMS_GROUPING.add(new MenuItem(com.pspdfkit.R.id.pspdf__annotation_creation_toolbar_item_underline)); SEVEN_ITEMS_GROUPING.add(new MenuItem(com.pspdfkit.R.id.pspdf__annotation_creation_toolbar_item_picker)); SEVEN_ITEMS_GROUPING.add(new MenuItem(com.pspdfkit.R.id.pspdf__annotation_creation_toolbar_item_image)); } }
Now let’s create an activity where we can listen to the annotation creation toolbar being displayed and apply our own structure and add a custom item to it:
class MyCustomActivity : PdfActivity(), ToolbarCoordinatorLayout.OnContextualToolbarLifecycleListener { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setOnContextualToolbarLifecycleListener(this) } override fun onPrepareContextualToolbar(toolbar: ContextualToolbar<*>) { if (toolbar is AnnotationCreationToolbar) { toolbar.setMenuItemGroupingRule(CustomAnnotationCreationToolbarGroupingRule(this)) // Get the existing menu items so we can add our item later. val menuItems = toolbar.menuItems // Create our custom menu item. val customItem = ContextualToolbarMenuItem.createSingleItem( this, R.id.pspdf_menu_custom, ContextCompat.getDrawable(this, R.drawable.ic_bookmark_outline), "Bookmark", Color.WHITE, Color.WHITE, ContextualToolbarMenuItem.Position.START, false ) // Tell the toolbar about our new item. menuItems.add(customItem) toolbar.setMenuItems(menuItems) // Add a listener so we can handle clicking on our item. toolbar.setOnMenuItemClickListener( ContextualToolbar.OnMenuItemClickListener { toolbar, menuItem -> return@OnMenuItemClickListener ( if (menuItem.id == R.id.pspdf_menu_custom) { Toast.makeText(this@MyCustomActivity, "Custom Action clicked", Toast.LENGTH_SHORT).show() true } else false ) } ) } ... }
public class MyCustomActivity extends PdfActivity implements ToolbarCoordinatorLayout.OnContextualToolbarLifecycleListener { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setOnContextualToolbarLifecycleListener(this); } @Override public void onPrepareContextualToolbar(@NonNull ContextualToolbar toolbar) { if (toolbar instanceof AnnotationCreationToolbar) { toolbar.setMenuItemGroupingRule(new CustomAnnotationCreationToolbarGroupingRule(this)); // Get the existing menu items so we can add our item later. final List<ContextualToolbarMenuItem> menuItems = ((AnnotationCreationToolbar) toolbar).getMenuItems(); // Create our custom menu item. final ContextualToolbarMenuItem customItem = ContextualToolbarMenuItem.createSingleItem( this, R.id.pspdf_menu_custom, ContextCompat.getDrawable(this, R.drawable.ic_bookmark_outline), "Bookmark", Color.WHITE, Color.WHITE, ContextualToolbarMenuItem.Position.START, false ); // Tell the toolbar about our new item. menuItems.add(customItem); toolbar.setMenuItems(menuItems); // Add a listener so we can handle clicking on our item. toolbar.setOnMenuItemClickListener(new ContextualToolbar.OnMenuItemClickListener() { @Override public boolean onToolbarMenuItemClick(@NonNull ContextualToolbar toolbar, @NonNull ContextualToolbarMenuItem menuItem) { if (menuItem.getId() == R.id.pspdf_menu_custom) { Toast.makeText(MyCustomActivity.this, "Custom Action clicked", Toast.LENGTH_SHORT).show(); return true; } return false; } }); } } }
Group MenuItems
When creating a MenuItem
with subitems, keep the following two points in mind:
-
For your
id
, always use one of the IDs marked asgroup
, e.g.pspdf__annotation_creation_toolbar_group_drawing
and notpspdf__annotation_creation_toolbar_item_underline
. This is to ensure you don’t accidentally use the same ID twice — for example, usingpspdf__annotation_creation_toolbar_item_underline
both for the group ID and as an actual item inside the menu. Using an ID marked asgroup
also makes the difference between group items and their children more obvious. Starting with PSPDFKit 7 for Android, this will be enforced and an exception will be thrown if an invalid ID is passed in for a group item. -
A group item in the
AnnotationCreationToolbar
never has its own icon. Instead, it will always look like the last item that was selected from the subgroup. This doesn’t apply in other toolbars where some group items get their own special icon — for example,pspdf__document_editing_toolbar_group_more
will result in an ellipsis icon instead of using one of the child icons, orpspdf__annotation_editing_toolbar_group_undo_redo
will result in a special icon showing if undo/redo is available.
Toolbar Positions
You can programmatically set the position of a toolbar or lock the toolbar into a specific position using ToolbarCoordinatorLayout.LayoutParams
. To set the toolbar to a specific position, you can call setPosition()
directly on the toolbar instance you want to move:
override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) // This example will move every toolbar that is shown to the user to the right position. setOnContextualToolbarLifecycleListener(object : OnContextualToolbarLifecycleListener { override fun onPrepareContextualToolbar(toolbar: ContextualToolbar) { toolbar.position = ToolbarCoordinatorLayout.LayoutParams.Position.RIGHT } ... }) }
@Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); // This example will move every toolbar that is shown to the user to the right position. setOnContextualToolbarLifecycleListener(new OnContextualToolbarLifecycleListener() { @Override public void onPrepareContextualToolbar(@NonNull ContextualToolbar toolbar) { toolbar.setPosition(ToolbarCoordinatorLayout.LayoutParams.Position.RIGHT); } ... }); }
Lock Toolbar into Position
You can also permanently lock a toolbar to a specific position by limiting the allowedPositions
using the toolbar’s ToolbarCoordinatorLayout.LayoutParams
:
override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) // This example will lock every toolbar to the left position, // making you unable to drag the toolbar to a different position. setOnContextualToolbarLifecycleListener(object : OnContextualToolbarLifecycleListener { override fun onPrepareContextualToolbar(toolbar: ContextualToolbar) { toolbar.layoutParams = ToolbarCoordinatorLayout.LayoutParams( Position.LEFT, EnumSet.of(Position.LEFT) )) } ... }) }
@Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); // This example will lock every toolbar to the left position, // making you unable to drag the toolbar to a different position. setOnContextualToolbarLifecycleListener(new OnContextualToolbarLifecycleListener() { @Override public void onPrepareContextualToolbar(@NonNull ContextualToolbar toolbar) { toolbar.setLayoutParams(new ToolbarCoordinatorLayout.LayoutParams( Position.LEFT, EnumSet.of(Position.LEFT) )); } ... }); }