This HTML page is not optimized for LLM or AI agent consumption. Fetch the Markdown version instead: /guides/android/samples/custom-annotation-creation-toolbar-java.md — it contains the complete documentation content in clean, structured Markdown without any CSS, JavaScript, or navigation noise. Custom Annotation Creation Toolbar

Add custom items to the annotation creation toolbar bound to specific tools and variants.


/*
* Copyright © 2019-2026 PSPDFKit GmbH. All rights reserved.
*
* The PSPDFKit Sample applications are licensed with a modified BSD license.
* Please see License for details. This notice may not be removed from this file.
*/
package com.pspdfkit.catalog.examples.java;
import static com.pspdfkit.catalog.tasks.ExtractAssetTask.extract;
import android.content.Context;
import android.content.Intent;
import android.graphics.Color;
import android.graphics.drawable.Drawable;
import android.net.Uri;
import android.os.Bundle;
import android.util.Pair;
import android.util.SparseArray;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.appcompat.content.res.AppCompatResources;
import com.pspdfkit.annotations.configuration.AnnotationConfigurationRegistry;
import com.pspdfkit.annotations.configuration.LineAnnotationConfiguration;
import com.pspdfkit.catalog.R;
import com.pspdfkit.catalog.SdkExample;
import com.pspdfkit.configuration.activity.PdfActivityConfiguration;
import com.pspdfkit.document.PdfDocument;
import com.pspdfkit.ui.PdfActivity;
import com.pspdfkit.ui.PdfActivityIntentBuilder;
import com.pspdfkit.ui.PdfFragment;
import com.pspdfkit.ui.special_mode.controller.AnnotationTool;
import com.pspdfkit.ui.special_mode.controller.AnnotationToolVariant;
import com.pspdfkit.ui.toolbar.AnnotationToolbar;
import com.pspdfkit.ui.toolbar.ContextualToolbar;
import com.pspdfkit.ui.toolbar.ContextualToolbarMenuItem;
import com.pspdfkit.ui.toolbar.ToolbarCoordinatorLayout;
import com.pspdfkit.ui.toolbar.grouping.presets.MenuItem;
import com.pspdfkit.ui.toolbar.grouping.presets.PresetMenuItemGroupingRule;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
/**
* Example showing how to use custom annotation creation toolbar item and bind it to the annotation
* tool and variant.
*/
public class CustomAnnotationCreationToolbarExample extends SdkExample {
public CustomAnnotationCreationToolbarExample(@NonNull Context context) {
super(
context,
R.string.customAnnotationCreationToolbarExampleTitle,
R.string.customAnnotationCreationToolbarExampleDescription);
}
@Override
public void launchExample(@NonNull Context context, @NonNull PdfActivityConfiguration.Builder configuration) {
// We use a custom utility class to extract the example document from the assets.
extract(WELCOME_DOC, getTitle(), context, documentFile -> {
final Intent intent = PdfActivityIntentBuilder.fromUri(context, Uri.fromFile(documentFile))
.configuration(configuration.build())
.activityClass(CustomAnnotationCreationToolbarActivity.class)
.build();
context.startActivity(intent);
});
}
/**
* This example shows how to manipulate annotation creation toolbar to add your own annotation tool
* items. In this example we add three line annotation tools, each of them for drawing lines of
* different colors.
*/
public static class CustomAnnotationCreationToolbarActivity extends PdfActivity
implements ToolbarCoordinatorLayout.OnContextualToolbarLifecycleListener,
AnnotationToolbar.ItemToAnnotationToolMapper {
// Variants of the line tool that we will add.
private static final String VARIANT_NAME_LINE_BLUE = "blue_line";
private static final String VARIANT_NAME_LINE_RED = "red_line";
private static final String VARIANT_NAME_LINE_YELLOW = "yellow_line";
// Icons for custom toolbar items.
@Nullable
private Drawable blueLineIcon;
@Nullable
private Drawable redLineIcon;
@Nullable
private Drawable yellowLineIcon;
@Override
public void onCreate(final Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// First we set the listener for the toolbar lifecycle changes so we
// can observe when the toolbar is being prepared, shown or dismissed
// inside the activity's UI.
setOnContextualToolbarLifecycleListener(this);
blueLineIcon = AppCompatResources.getDrawable(this, com.pspdfkit.R.drawable.pspdf__ic_line);
// The red line uses a customized colored drawable. So tinting must be disabled.
redLineIcon = AppCompatResources.getDrawable(this, R.drawable.ic_line_red);
yellowLineIcon = AppCompatResources.getDrawable(this, com.pspdfkit.R.drawable.pspdf__ic_line);
}
@Override
public void onDocumentLoaded(@NonNull final PdfDocument document) {
super.onDocumentLoaded(document);
final PdfFragment pdfFragment = getPdfFragment();
if (pdfFragment != null) {
// Here we set editing defaults for the items we're gonna create.
final AnnotationConfigurationRegistry annotationConfiguration =
pdfFragment.getAnnotationConfiguration();
// Blue line configuration.
annotationConfiguration.put(
AnnotationTool.LINE,
AnnotationToolVariant.fromName(VARIANT_NAME_LINE_BLUE),
LineAnnotationConfiguration.builder(this) // Use preset configuration for creating lines.
.setDefaultColor(Color.BLUE) // Use blue as a default color.
.setAvailableColors(Collections.singletonList(Color.BLUE)) // Only allow blue to be set.
.setForceDefaults(true) // Always force these defaults.
.setCustomColorPickerEnabled(false)
.build());
// Red line configuration.
annotationConfiguration.put(
AnnotationTool.LINE,
AnnotationToolVariant.fromName(VARIANT_NAME_LINE_RED),
LineAnnotationConfiguration.builder(this) // Use preset configuration for creating lines.
.setDefaultColor(Color.RED) // Use red as a default color.
.setAvailableColors(Collections.singletonList(Color.RED)) // Only allow red to be set.
.setForceDefaults(true) // Always force these defaults.
.setCustomColorPickerEnabled(false)
.build());
// Yellow line configuration.
annotationConfiguration.put(
AnnotationTool.LINE,
AnnotationToolVariant.fromName(VARIANT_NAME_LINE_YELLOW),
LineAnnotationConfiguration.builder(this) // Use preset configuration for creating lines.
.setDefaultColor(Color.YELLOW) // Use yellow as a default color.
.setAvailableColors(
Collections.singletonList(Color.YELLOW)) // Only allow yellow to be set.
.setForceDefaults(true) // Always force these defaults.
.setCustomColorPickerEnabled(false)
.build());
}
}
@Override // ToolbarCoordinatorLayout.OnContextualToolbarLifecycleListener
public void onPrepareContextualToolbar(@NonNull final ContextualToolbar toolbar) {
if (toolbar instanceof AnnotationToolbar annotationToolbar) {
// Register this class as a mapper (see implemented methods below).
annotationToolbar.setItemToAnnotationToolMapper(this);
// Register grouping rule to tell toolbar how to group menu items.
annotationToolbar.setMenuItemGroupingRule(new CustomAnnotationCreationToolbarGroupingRule(this));
final List<ContextualToolbarMenuItem> customMenuItems = new ArrayList<>();
if (blueLineIcon != null) {
final ContextualToolbarMenuItem blueLineItem = ContextualToolbarMenuItem.createSingleItem(
this,
R.id.line_blue,
blueLineIcon,
"Line: Blue",
Color.GRAY,
Color.BLUE,
ContextualToolbarMenuItem.Position.START,
true);
customMenuItems.add(blueLineItem);
}
if (redLineIcon != null) {
final ContextualToolbarMenuItem redLineItem = ContextualToolbarMenuItem.createSingleItem(
this,
R.id.line_red,
redLineIcon,
"Line: Red",
Color.WHITE,
Color.BLUE,
ContextualToolbarMenuItem.Position.START,
true);
// Disabling tinting as the red line drawable
// is a colored one.
redLineItem.setTintingEnabled(false);
customMenuItems.add(redLineItem);
}
if (yellowLineIcon != null) {
final ContextualToolbarMenuItem yellowLineItem = ContextualToolbarMenuItem.createSingleItem(
this,
R.id.line_yellow,
yellowLineIcon,
"Line: Yellow",
Color.GRAY,
Color.BLUE,
ContextualToolbarMenuItem.Position.START,
true);
customMenuItems.add(yellowLineItem);
}
// Before we pass custom items, we need to include our default ones as well.
customMenuItems.addAll(annotationToolbar.getMenuItems());
annotationToolbar.setMenuItems(customMenuItems);
}
}
@Override // ToolbarCoordinatorLayout.OnContextualToolbarLifecycleListener
public void onDisplayContextualToolbar(@NonNull final ContextualToolbar toolbar) {}
@Override // ToolbarCoordinatorLayout.OnContextualToolbarLifecycleListener
public void onRemoveContextualToolbar(@NonNull final ContextualToolbar toolbar) {}
@NonNull
@Override // AnnotationToolbar.ItemToAnnotationToolMapper
public SparseArray<Pair<AnnotationTool, AnnotationToolVariant>> getItemToAnnotationToolMapping() {
// We need to add mappings to let toolbar know which item should handle which tool/variant.
final SparseArray<Pair<AnnotationTool, AnnotationToolVariant>> itemToAnnotationToolMapping =
new SparseArray<>();
itemToAnnotationToolMapping.put(
R.id.line_blue,
new Pair<>(AnnotationTool.LINE, AnnotationToolVariant.fromName(VARIANT_NAME_LINE_BLUE)));
itemToAnnotationToolMapping.put(
R.id.line_red,
new Pair<>(AnnotationTool.LINE, AnnotationToolVariant.fromName(VARIANT_NAME_LINE_RED)));
itemToAnnotationToolMapping.put(
R.id.line_yellow,
new Pair<>(AnnotationTool.LINE, AnnotationToolVariant.fromName(VARIANT_NAME_LINE_YELLOW)));
return itemToAnnotationToolMapping;
}
@Override // AnnotationToolbar.ItemToAnnotationToolMapper
public boolean isStyleIndicatorCircleEnabled(final int itemId) {
// We want to show style indicators for all our custom items and not show it for all the
// default ones.
return getItemToAnnotationToolMapping().get(itemId) != null;
}
/**
* Class that implements the {@link PresetMenuItemGroupingRule}, used to tell the toolbar how to
* group menu items in the toolbar.
*
* @see com.pspdfkit.catalog.ui.CustomAnnotationCreationToolbarGroupingRule for more details.
*/
private static class CustomAnnotationCreationToolbarGroupingRule extends PresetMenuItemGroupingRule {
private final List<MenuItem> CUSTOM_GROUPING = new ArrayList<>(4);
CustomAnnotationCreationToolbarGroupingRule(@NonNull final Context context) {
super(context);
// This adds our default markup items under out default markup group item.
CUSTOM_GROUPING.add(new MenuItem(com.pspdfkit.R.id.pspdf__annotation_toolbar_group_markup, new int[] {
com.pspdfkit.R.id.pspdf__annotation_toolbar_item_highlight,
com.pspdfkit.R.id.pspdf__annotation_toolbar_item_squiggly,
com.pspdfkit.R.id.pspdf__annotation_toolbar_item_strikeout,
com.pspdfkit.R.id.pspdf__annotation_toolbar_item_underline,
com.pspdfkit.R.id.pspdf__annotation_toolbar_item_line
}));
// This adds line items under our group item ('writing' in this case). You can also use
// your own
// but then you need to add them to the menu items.
CUSTOM_GROUPING.add(new MenuItem(
com.pspdfkit.R.id.pspdf__annotation_toolbar_group_writing,
new int[] {R.id.line_blue, R.id.line_red, R.id.line_yellow}));
// Some standalone item from the default framework implementation.
CUSTOM_GROUPING.add(new MenuItem(com.pspdfkit.R.id.pspdf__annotation_toolbar_item_ink_highlighter));
// To access the property inspector, the color picker item needs to be added as well.
CUSTOM_GROUPING.add(new MenuItem(com.pspdfkit.R.id.pspdf__annotation_toolbar_item_picker));
}
@NonNull
@Override
public List<MenuItem> getGroupPreset(final int capacity, final int itemsCount) {
// Capacity shouldn't be less than 4. If that is the case, return empty list.
if (capacity < ContextualToolbar.MIN_TOOLBAR_CAPACITY) return new ArrayList<>(capacity);
// Return our custom groupings for all other capacities.
return CUSTOM_GROUPING;
}
@Override
public boolean areGeneratedGroupItemsSelectable() {
return true;
}
}
}
}

This code sample is an example that illustrates how to use our SDK. Please adapt it to your specific use case.