Example showing how to use custom items in annotation creation toolbar and bind them to the annotation tool and variant.


/*
* 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.AnnotationCreationToolbar;
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,
AnnotationCreationToolbar.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
protected 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 AnnotationCreationToolbar annotationCreationToolbar) {
// Register this class as a mapper (see implemented methods below).
annotationCreationToolbar.setItemToAnnotationToolMapper(this);
// Register grouping rule to tell toolbar how to group menu items.
annotationCreationToolbar.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(annotationCreationToolbar.getMenuItems());
annotationCreationToolbar.setMenuItems(customMenuItems);
}
}
@Override // ToolbarCoordinatorLayout.OnContextualToolbarLifecycleListener
public void onDisplayContextualToolbar(@NonNull final ContextualToolbar toolbar) {}
@Override // ToolbarCoordinatorLayout.OnContextualToolbarLifecycleListener
public void onRemoveContextualToolbar(@NonNull final ContextualToolbar toolbar) {}
@NonNull
@Override // AnnotationCreationToolbar.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 // AnnotationCreationToolbar.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_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,
com.pspdfkit.R.id.pspdf__annotation_creation_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_creation_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_creation_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_creation_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.