Effortlessly customize text selection in Android
The TextSelectionManager
interface contains OnTextSelectionModeChangeListener
and OnTextSelectionChangeListener
, which can be used to listen for text selection changes. The default PdfActivity
implementation will display a contextual toolbar — namely TextSelectionToolbar
— when the text is long-pressed and the text selection mode starts. The toolbar provides seven actions for selected text: copy, highlight, redact, speak, search, share, and create a link.
Registering custom listeners
You can create custom listeners for TextSelectionManager
to handle changes in text selection and text selection mode (entering and exiting):
class MyActivity : PdfActivity(), TextSelectionManager.OnTextSelectionChangeListener, TextSelectionManager.OnTextSelectionModeChangeListener {
const val TAG = "MyActivity.TextSelection"
override fun onCreate(savedInstanceState: Bundle?) { PdfFragment.addOnTextSelectionModeChangeListener(this) PdfFragment.addOnTextSelectionChangeListener(this) }
override fun onDestroy(savedInstanceState: Bundle?) { PdfFragment.removeOnTextSelectionModeChangeListener(this) PdfFragment.removeOnTextSelectionChangeListener(this) }
override fun onEnterTextSelectionMode(controller: TextSelectionController) { Log.i(TAG, "Text selection mode has started.") }
override fun onExitTextSelectionMode(controller: TextSelectionController) { Log.i(TAG, "Text selection mode has ended.") }
override fun onTextSelectionChange(newTextSelection: TextSelection?, currentTextSelection: TextSelection?): Boolean { if (newTextSelection != null) { Log.i(TAG, "Selected text was: ${newTextSelection.text}") } else { Log.i(TAG, "Text selection is cleared.") } // Return `false` to prevent changes to the current selection state, if needed. return true }}
public class MyActivity extends PdfActivity implements TextSelectionManager.OnTextSelectionChangeListener, TextSelectionManager.OnTextSelectionModeChangeListener{
private static final String TAG = "MyActivity.TextSelection";
@Override protected void onCreate(Bundle savedInstanceState) { getPdfFragment().addOnTextSelectionModeChangeListener(this); getPdfFragment().addOnTextSelectionChangeListener(this); }
@Override protected void onDestroy(Bundle savedInstanceState) { getPdfFragment().removeOnTextSelectionModeChangeListener(this); getPdfFragment().removeOnTextSelectionChangeListener(this); }
@Override public void onEnterTextSelectionMode(@NonNull TextSelectionController controller) { Log.i(TAG, "Text selection mode has started."); }
@Override public void onExitTextSelectionMode(@NonNull TextSelectionController controller) { Log.i(TAG, "Text selection mode has ended."); }
@Override public boolean onTextSelectionChange(@Nullable TextSelection newTextSelection, @Nullable TextSelection currentTextSelection) { if (newTextSelection != null) { Log.i(TAG, String.format("Selected text was: %s", newTextSelection.text)); } else { Log.i(TAG, "Text selection is cleared."); }
// Return `false` to prevent changes to the current selection state, if needed. return true; }}
By implementing these listeners, you can add custom reactions to text selection events.
This setup doesn’t override the default behavior — it only adds additional listeners. If you need to completely change the behavior (e.g. replacing the toolbar with a custom user interface), use PdfFragment
in a custom activity and bind it to the TextSelectionController
.
Customizing text selection actions
The text selection toolbar can also be customized. This toolbar is only visible when the standard Android-style text selection popup menu is disabled. To disable the text selection popup and enable the text selection toolbar, set the textSelectionPopupToolbarEnabled
property to false
in the PdfConfiguration
:
val configuration = PdfConfiguration.Builder().textSelectionPopupToolbarEnabled(false).build()
PdfConfiguration configuration = new PdfConfiguration.Builder().textSelectionPopupToolbarEnabled(false).build();
The default text selection actions can be modified using toolbar.setMenuItems(...)
. To access the TextSelectionToolbar
, register the OnContextualToolbarLifecycleListener
and configure the actions inside its #onPrepareContextualToolbar
method:
class MyActivity : PdfActivity(), ToolbarCoordinatorLayout.OnContextualToolbarLifecycleListener {
private lateinit var customTextSelectionAction: ContextualToolbarMenuItem
override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState)
// Register the activity as a callback for contextual toolbar changes. // It will be called once the `TextSelectionToolbar` is going to be presented. setOnContextualToolbarLifecycleListener(this)
// Create a custom menu item that will be shown inside the text selection toolbar. customTextSelectionAction = ContextualToolbarMenuItem.create( this, R.id.custom_text_action, AppCompatDrawableManager.get().getDrawable(this, R.drawable.ic_my_action), "Custom text action", Color.WHITE, Color.RED, false) }
override fun onPrepareContextualToolbar(toolbar: ContextualToolbar) { // Add the custom action once the selection toolbar is being prepared. // At this point, you could also remove undesired actions from the toolbar. if (toolbar is TextSelectionToolbar) { val menuItems = toolbar.getMenuItems() if (!menuItems.contains(customTextSelectionAction)) { menuItems.add(customTextSelectionAction) toolbar.setMenuItems(menuItems) } } }
override fun onDisplayContextualToolbar(toolbar: ContextualToolbar) { // Register a click listener to handle taps on the custom text selection action. toolbar.setOnMenuItemClickListener { toolbar, menuItem -> var handled = false
if (menuItem.id == R.id.custom_text_action) { handled = true Toast.makeText(this@MyActivity, "Text selection action triggered!", Toast.LENGTH_SHORT) .show() }
handled } }
override fun onRemoveContextualToolbar(toolbar: ContextualToolbar) { toolbar.setOnMenuItemClickListener(null) }}
public class MyActivity extends PdfActivity implements ToolbarCoordinatorLayout.OnContextualToolbarLifecycleListener {
private ContextualToolbarMenuItem customTextSelectionAction;
@Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState);
// Register the activity as a callback for contextual toolbar changes. // It will be called once the `TextSelectionToolbar` is going to be presented. setOnContextualToolbarLifecycleListener(this);
// Create a custom menu item that will be shown inside the text selection toolbar. customTextSelectionAction = ContextualToolbarMenuItem.create( this, R.id.custom_text_action, AppCompatDrawableManager.get().getDrawable(this, R.drawable.ic_my_action), "Custom text action", Color.WHITE, Color.RED, false ); }
@Override public void onPrepareContextualToolbar(@NonNull ContextualToolbar toolbar) { // Add the custom action once the selection toolbar is being prepared. // At this point, you could also remove undesired actions from the toolbar. if (toolbar instanceof TextSelectionToolbar) { final List<ContextualToolbarMenuItem> menuItems = toolbar.getMenuItems(); if (!menuItems.contains(customTextSelectionAction)) { menuItems.add(customTextSelectionAction); toolbar.setMenuItems(menuItems); } } }
@Override public void onDisplayContextualToolbar(@NonNull ContextualToolbar toolbar) { // Register a click listener to handle taps on the custom text selection action. toolbar.setOnMenuItemClickListener((contextualToolbar, menuItem) -> { boolean handled = false;
if (menuItem.getId() == R.id.custom_text_action) { handled = true; Toast.makeText(MyActivity.this, "Text selection action triggered!", Toast.LENGTH_SHORT) .show(); }
return handled; }); }
@Override public void onRemoveContextualToolbar(@NonNull ContextualToolbar toolbar) { toolbar.setOnMenuItemClickListener(null); }}
Selecting text programmatically
You can select text programmatically by calling PdfFragment#enterTextSelectionMode
and providing the text range to be selected. You can retrieve the text of the current page by calling PdfDocument#getPageText
.
For example, select the first occurrence of a random string on the page:
// Search for the position of text that should be selected.val textToSelect = "text to select"val textIndexOnPage = document.getPageText(pageIndex).indexOf(textToSelect)if (textIndexOnPage >= 0) { // Select the text. fragment.enterTextSelectionMode(pageIndex, Range(textIndexOnPage, textToSelect.length))}
// Search for the position of text that should be selected.String textToSelect = "text to select";int textIndexOnPage = document.getPageText(pageIndex).indexOf(textToSelect);if (textIndexOnPage >= 0) { // Select the text. fragment.enterTextSelectionMode(pageIndex, new Range(textIndexOnPage, textToSelect.length()));}