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
}
}

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()

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)
}
}

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))
}