UI Customization
In addition to the core feature modules, the ComPDF SDK also provides the ComPDFKit_Tools module. This module includes a complete set of built-in UI components and interaction logic, enabling rapid integration on top of the core capabilities while supporting flexible extension and customization.
In addition, we provide a sample application PDFViewer, which demonstrates the integration and usage of ComPDFKit_Tools for developers’ reference.
This chapter introduces ComPDFKit_Tools from the following aspects:
- Overview: Description of module features and UI examples
- Integration: How to quickly integrate and use ComPDFKit_Tools
- Customization: How to customize UI and functionality
Overview
The ComPDFKit_Tools module integrates common PDF viewing and editing capabilities, including but not limited to:
- Viewer
- Annotations
- Forms
- Content Editor
- Page Editor
- Digital Signatures
- Security & Watermark
By using CPDFDocumentActivity or CPDFDocumentFragment, you can quickly launch a complete PDF document interface in your project. UI behavior and functional modules can be controlled through configuration files; for deeper customization, you can also directly use the ComPDFKit_Tools module source code for secondary development.
SDK Integration
The SDK supports multiple integration methods. You can choose an appropriate solution based on your project requirements.
Version & Compatibility (Recommended)
- Keep consistent with core modules: the
compdfkit-toolsversion must matchcompdfkitandcompdfkit-ui.- Android version: please select appropriate
minSdk/compileSdk/targetSdkand AGP versions according to the SDK release notes.- R8 / ProGuard: if code obfuscation is enabled, please refer to the obfuscation rules provided with the SDK.
Gradle Integration
- Open the "settings.gradle" file in the project root directory, then add the mavenCentral repository:
dependencyResolutionManagement {
repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS)
repositories {
google()
+ mavenCentral()
}
}- Open the "build.gradle" file in the application module directory:

Edit it and add the ComPDFKit_Tools module dependency:
def compdfkitVersion = "2.6.0" // Keep consistent with compdfkit / compdfkit-ui versions
dependencies {
implementation "com.compdf:compdfkit-tools:$compdfkitVersion"
// Or depend on the core and UI modules separately (versions must be consistent):
// implementation "com.compdf:compdfkit:$compdfkitVersion"
// implementation "com.compdf:compdfkit-ui:$compdfkitVersion"
}Manual Integration
- Copy "ComPDFKit-Tools.aar" into the "libs" directory of the app module.

- Add the following code to the "build.gradle" file under the app directory:
...
dependencies {
/* ComPDFKit SDK */
implementation fileTree(dir: 'libs', include: ['*.jar', '*.aar'])
...
}
...Please make sure to also manually integrate ComPDFKit.aar and ComPDFKit-UI.aar as described in Section 2.5.2 to ensure proper operation.
Source Code Integration
You can obtain the ComPDFKit_Tools module source code from the SDK package or the GitHub sample project.
- Download or extract the SDK source code
- In Android Studio, import the module via File → New → Import Module

- Add the following in
app/build.gradle:
dependencies {
implementation project(path: ':ComPDFKit_Tools')
}Usage
After completing module integration, you can launch the document interface via CPDFDocumentActivity or CPDFDocumentFragment. UI and feature configurations are controlled via CPDFConfiguration. The default configuration file is tools_default_configuration.json.
Tip (Android 10 / 11+ Storage Access)
- It is recommended to open and save documents using
Uri(SAF / MediaStore). Direct file paths may be restricted by Scoped Storage on newer Android versions.tools_default_configuration.jsonis packaged by default in the Tools moduleassetsdirectory and can be used directly or copied into the appassetsdirectory to override the default configuration.
Minimum example (open via Uri, Activity mode):
Intent intent = new Intent(context, CPDFDocumentActivity.class);
intent.setData(uri); // Uri returned by SAF picker
intent.putExtra(CPDFDocumentActivity.EXTRA_FILE_PASSWORD, password); // Optional
CPDFConfiguration configuration = CPDFConfigurationUtils.normalConfig(context, "tools_default_configuration.json");
intent.putExtra(CPDFDocumentActivity.EXTRA_CONFIGURATION, configuration);
intent.putExtra(CPDFDocumentActivity.EXTRA_PAGE_INDEX, 0);
context.startActivity(intent);
val intent = Intent(context, CPDFDocumentActivity::class.java).apply {
data = uri // Uri returned by SAF picker
putExtra(CPDFDocumentActivity.EXTRA_FILE_PASSWORD, password) // Optional
val configuration = CPDFConfigurationUtils.normalConfig(context, "tools_default_configuration.json")
putExtra(CPDFDocumentActivity.EXTRA_CONFIGURATION, configuration)
putExtra(CPDFDocumentActivity.EXTRA_PAGE_INDEX, 0)
}
context.startActivity(intent)- Open a PDF file via Uri path
// CPDFDocumentActivity
Intent intent = new Intent(context, CPDFDocumentActivity.class);
intent.setData(uri);
// Password is optional
intent.putExtra(CPDFDocumentActivity.EXTRA_FILE_PASSWORD, password);
// tools_default_configuration.json is included in the Tools module assets directory
CPDFConfiguration configuration = CPDFConfigurationUtils.normalConfig(context, "tools_default_configuration.json");
intent.putExtra(CPDFDocumentActivity.EXTRA_CONFIGURATION, configuration);
// Default page index when opening
intent.putExtra(CPDFDocumentActivity.EXTRA_PAGE_INDEX, 0);
context.startActivity(intent);
// CPDFDocumentFragment
CPDFConfiguration configuration = CPDFConfigurationUtils.normalConfig(context, "tools_default_configuration.json");
CPDFDocumentFragment documentFragment = CPDFDocumentFragment.newInstance(uri, "password", configuration);
getSupportFragmentManager()
.beginTransaction()
.replace(R.id.fragment_container_view, documentFragment, "documentFragment")
.commit();// CPDFDocumentActivity
val intent = Intent(context, CPDFDocumentActivity::class.java).apply {
data = uri // Uri returned by SAF picker
putExtra(CPDFDocumentActivity.EXTRA_FILE_PASSWORD, password) // Password is optional
// tools_default_configuration.json is included in the Tools module assets directory
val configuration = CPDFConfigurationUtils.normalConfig(context, "tools_default_configuration.json")
putExtra(CPDFDocumentActivity.EXTRA_CONFIGURATION, configuration)
putExtra(CPDFDocumentActivity.EXTRA_PAGE_INDEX, 0) // Default page index when opening
}
context.startActivity(intent)
// CPDFDocumentFragment
val configuration = CPDFConfigurationUtils.normalConfig(context, "tools_default_configuration.json")
val documentFragment = CPDFDocumentFragment.newInstance(uri, "password", configuration)
supportFragmentManager
.beginTransaction()
.replace(R.id.fragment_container_view, documentFragment, "documentFragment")
.commit()- Open a PDF file via file path (note Scoped Storage restrictions)
// CPDFDocumentActivity
Intent intent = new Intent(context, CPDFDocumentActivity.class);
intent.putExtra(CPDFDocumentActivity.EXTRA_FILE_PATH, filePath);
// Password is optional
intent.putExtra(CPDFDocumentActivity.EXTRA_FILE_PASSWORD, password);
// tools_default_configuration.json is included in the Tools module assets directory
CPDFConfiguration configuration = CPDFConfigurationUtils.normalConfig(context, "tools_default_configuration.json");
intent.putExtra(CPDFDocumentActivity.EXTRA_CONFIGURATION, configuration);
// Default page index when opening
intent.putExtra(CPDFDocumentActivity.EXTRA_PAGE_INDEX, 0);
context.startActivity(intent);
// CPDFDocumentFragment
CPDFConfiguration configuration = CPDFConfigurationUtils.normalConfig(context, "tools_default_configuration.json");
CPDFDocumentFragment documentFragment = CPDFDocumentFragment.newInstance(filePath, password, configuration);
getSupportFragmentManager()
.beginTransaction()
.replace(R.id.fragment_container_view, documentFragment, "documentFragment")
.commit();// CPDFDocumentActivity
val intent = Intent(context, CPDFDocumentActivity::class.java).apply {
putExtra(CPDFDocumentActivity.EXTRA_FILE_PATH, filePath) // File path
putExtra(CPDFDocumentActivity.EXTRA_FILE_PASSWORD, password) // Password is optional
// tools_default_configuration.json is included in the Tools module assets directory
val configuration = CPDFConfigurationUtils.normalConfig(context, "tools_default_configuration.json")
putExtra(CPDFDocumentActivity.EXTRA_CONFIGURATION, configuration)
putExtra(CPDFDocumentActivity.EXTRA_PAGE_INDEX, 0) // Default page index when opening
}
context.startActivity(intent)
// CPDFDocumentFragment
val configuration = CPDFConfigurationUtils.normalConfig(context, "tools_default_configuration.json")
val documentFragment = CPDFDocumentFragment.newInstance(filePath, password, configuration)
supportFragmentManager
.beginTransaction()
.replace(R.id.fragment_container_view, documentFragment, "documentFragment")
.commit()After running, the result is shown below:

Customization
This section describes how to customize the functionality and UI of ComPDFKit_Tools through configuration files, including:
- Enabling / disabling feature modules
- Setting default attributes
- Customizing toolbars and menus
- Customizing context menus
- Adding event callbacks
All examples are based on tools_default_configuration.json. You can copy this file into your project’s assets directory for modification and testing.
Custom Feature Modules
You can configure the default mode, available modes, and UI display behavior via modeConfig.
- Set the default mode (snippet example)
// tools_default_configuration.json
{
"modeConfig": {
// viewer, annotations, contentEditor, forms, signatures
"initialViewMode": "viewer"
}
}- Set the list of enabled modes (snippet example)
// tools_default_configuration.json
{
"modeConfig": {
"initialViewMode": "viewer",
"availableViewModes": [
"viewer",
"annotations",
"contentEditor",
"forms",
"signatures"
]
}
}- UI display mode (snippet example)
// tools_default_configuration.json
{
"modeConfig": {
// automatic : Automatic mode. Tap the PDF page to toggle fullscreen
// always : Always show top and bottom toolbars, no auto hiding
// never: Hide top and bottom toolbars and never show them
"uiVisibilityMode": "automatic"
}
}Use it when creating a CPDFDocumentFragment instance:
CPDFConfiguration configuration = CPDFConfigurationUtils.normalConfig(context, "tools_default_configuration.json");
CPDFDocumentFragment documentFragment = CPDFDocumentFragment.newInstance(uri, "password", configuration);The usage of
CPDFDocumentActivityis the same. Please refer to Section 2.6.3.
Set Default Attributes
You can uniformly set default styles for annotations, content editing, and forms in the configuration file, such as colors, transparency, and fonts.
// tools_default_configuration.json
{
"annotationsConfig": {
"initAttribute": {
"note": { // Note annotation attributes
"color": "#1460F3",
"alpha": 255 // Value range: 0–255
},
"highlight": { // Highlight annotation attributes
"color": "#1460F3",
"alpha": 77
},
"freeText": {
"fontColor": "#000000",
"fontColorAlpha": 255,
"fontSize": 30,
"alignment": "left",
"familyName": "Helvetica", // Font family name, see the Font Management section for details
"styleName": "Regular" // Font style
}
}
}
}Only part of the configuration is shown as an example. For the complete content, please refer to tools_default_configuration.json
- Set form attributes
// tools_default_configuration.json
{
"formsConfig": {
"initAttribute": {
"textField": { // Text field form attributes
"fillColor": "#DDE9FF",
"borderColor": "#1460F3",
"borderWidth": 2,
"fontColor": "#000000",
"fontSize": 20,
"alignment": "left",
"multiline": true,
"familyName": "Helvetica",
"styleName": "Regular"
},
"checkBox": { // Check box attributes
"fillColor": "#DDE9FF",
"borderColor": "#1460F3",
"borderWidth": 2,
"checkedColor": "#43474D",
"isChecked": false,
"checkedStyle": "check" // check, circle, cross, diamond, square, star
},
"listBox": { // List box attributes
"fillColor": "#DDE9FF",
"borderColor": "#1460F3",
"borderWidth": 2,
"fontColor": "#000000",
"fontSize": 20,
"familyName": "Helvetica",
"styleName": "Regular"
}
}
}
}Only part of the configuration is shown as an example. For the complete content, please refer to tools_default_configuration.json
Custom Toolbars
You can control the visibility of toolbars in different modes via toolbarConfig, and customize top toolbar menu items.
- Show / hide toolbars
// tools_default_configuration.json
{
"toolbarConfig": {
"mainToolbarVisible": true, // Show / hide top toolbar
"contentEditorToolbarVisible": true, // Show / hide content editor bottom toolbar
"annotationToolbarVisible": true, // Show / hide annotation mode bottom toolbar
"formToolbarVisible": true, // Show / hide form mode bottom toolbar
"signatureToolbarVisible": true // Show / hide signature mode bottom toolbar
}
}- Customize annotation toolbar
// tools_default_configuration.json
{
"annotationsConfig": {
"annotationAuthor": "Guest", // Author name of created annotations
"availableTypes": [ // Enabled annotation types
"note",
"highlight",
"underline",
"squiggly",
"strikeout",
"ink",
"ink_eraser",
"circle",
"square",
"arrow",
"line",
"freetext",
"signature",
"stamp",
"pictures",
"link",
"sound"
],
"availableTools": [ // Available tools
"setting",
"undo",
"redo"
]
}
}- Customize form toolbar
// tools_default_configuration.json
{
"formsConfig": {
"showCreateListBoxOptionsDialog": true, // Whether to show options dialog after creating a list box
"showCreateComboBoxOptionsDialog": true, // Whether to show options dialog after creating a combo box
"showCreatePushButtonOptionsDialog": true, // Whether to show options dialog after creating a button
"availableTypes": [ // Enabled form types
"textField",
"checkBox",
"radioButton",
"listBox",
"comboBox",
"signaturesFields",
"pushButton"
],
"availableTools": [ // Enabled form tool types
"undo",
"redo"
]
}
}- Customize top toolbar menu
The default configuration provides a fixed list of menu options, which supports hiding or reordering. Example configuration:
// tools_default_configuration.json
{
"toolbarConfig": {
"toolbarLeftItems": [
"back"
],
"toolbarRightItems": [
"thumbnail",
"search",
"bota",
"menu"
],
"availableMenus": [
"viewSettings",
"documentEditor",
"documentInfo",
"save",
"watermark",
"security",
"flattened",
"share",
"openDocument",
"snip"
]
}
}In addition, you can configure custom menu items to meet specific requirements.
- Modify menu item icons and text
If you need to modify the icon or text of default menu buttons, you can do so through custom menu configuration. The following example shows how to modify the icon and text of the More menu item in the toolbar:
// tools_default_configuration.json
{
"toolbarConfig": {
"customToolbarLeftItems": [], // Left toolbar items
"customToolbarRightItems": [], // Right toolbar items
"customMoreMenuItems": [ // More menu items
{
"action": "viewSettings", // ID corresponding to view settings
"icon": "ic_test_settings", // Button icon, image resource must be placed in res/drawable
"title": "Settings" // Menu text
}
]
}
}Please note that if custom menu items are configured, the corresponding toolbarLeftItems, toolbarRightItems, and availableMenus configurations will be disabled.
- Add custom menu items
You can also add custom buttons as needed. The following example shows how to add a “Download” button to the left toolbar menu. After clicking it, the document is saved and the file path is obtained:
// tools_default_configuration.json
{
"toolbarConfig": {
// Left toolbar items
"customToolbarLeftItems": [
{
"action": "custom", // The action value of a custom event button must be custom
"identifier": "custom_download_action", // Unique ID of the custom event, returned in callback when clicked
"icon": "ic_test_download", // Button icon, image resource must be placed in res/drawable
"title": "Download" // Only effective in customMoreMenuItems
}
],
// Right toolbar items
"customToolbarRightItems": [],
// More menu items
"customMoreMenuItems": []
}
}Add an event callback when using CPDFDocumentFragment:
CPDFDocumentFragment documentFragment = CPDFDocumentFragment.newInstance(uri, "password", configuration);
getSupportFragmentManager()
.beginTransaction()
.replace(R.id.fragment_container_view, documentFragment, "documentFragment")
.commit();
// Add callback
CPDFCustomEventCallbackHelper.getInstance().addCustomEventCallback(extraMap -> {
// First get the custom event type. There are multiple types, such as toolbar events and context menu events
String customEventType = extraMap.get(CPDFCustomEventField.CUSTOM_EVENT_TYPE).toString();
if (CPDFCustomEventType.TOOLBAR_ITEM_TAPPED.equals(customEventType)){
// Top toolbar button click event
String action = extraMap.get("identifier").toString();
switch (action){
case "custom_download_action":
CPDFViewCtrl pdfView = documentFragment.pdfView;
boolean saveIncremental = false;
boolean fontSubset = true;
pdfView.savePDF(saveIncremental, fontSubset, (filePath, pdfUri) -> {
// Get uri or file
CToastUtil.showToast(getApplicationContext(), "Saved successfully");
}, e -> {
});
break;
}
}
});
// Please remove the registered callback after CPDFDocumentFragment is no longer used
CPDFCustomEventCallbackHelper.getInstance().removeCustomEventCallback(this);By following the steps above, you can add and respond to a fully customized menu button.

Depending on the type of context menu, different data will be returned in extraMap. Please refer to the following description:
| Key | Value | Description |
|---|---|---|
| identifier | custom_markup_action_get_text | The option value defined in the custom context menu, a unique identifier |
| annotation | CPDFAnnotation | Returned when an annotation is selected |
| widget | CPDFWidget | Returned when a form field is selected |
| editArea | CPDFEditArea | Returned when text or images are selected in content editing mode |
| text | xxx | The selected text string when text is long-pressed |
| pageIndex | The page index where the selected text is located | |
| rect | The bounding rectangle of the selected text | |
| image | bitmap | The Bitmap image of the captured rectangular area from screenshot context |
| point | The tap position returned when long-pressing a blank area in content edit mode |
Add Callback Events
The ComPDFKit_Tools module provides a series of event callbacks in CPDFDocumentFragment, enabling advanced customization and interaction handling. Below are some commonly used callbacks:
Initialization Completed Callback
// Triggered when CPDFDocumentFragment successfully opens and finishes loading the document
documentFragment.setInitListener(pdfView -> {
});Save Document Callback
documentFragment.setInitListener(pdfView -> {
pdfView.setSaveCallback((filePath, pdfUri) -> {
// Save succeeded
}, e -> {
// Save failed
});
});Annotation Creation Callback
documentFragment.setAddAnnotCallback(new CPDFAddAnnotCallback() {
@Override
public void onAddAnnotation(CPDFPageView cpdfPageView, CPDFBaseAnnotImpl<CPDFAnnotation> cpdfBaseAnnot) {
}
});Annotation / Form Selection Callback
documentFragment.setInitListener(pdfView -> {
pdfView.getCPdfReaderView().setSelectAnnotCallback(new CPDFSelectAnnotCallback() {
@Override
public void onAnnotationSelected(CPDFPageView cpdfPageView, CPDFBaseAnnotImpl<CPDFAnnotation> cpdfBaseAnnot) {
}
@Override
public void onAnnotationDeselected(
CPDFPageView cpdfPageView,
@Nullable CPDFBaseAnnotImpl<CPDFAnnotation> cpdfBaseAnnot) {
}
});
});Content Editor Selection Callback
documentFragment.setInitListener(pdfView -> {
CPDFReaderView readerView = pdfView.getCPdfReaderView();
pdfView.addSelectEditAreaChangeListener(new OnSelectEditAreaChangeListener() {
@Override
public void onSelectEditAreaChange(int type) {
if (type == CEditToolbar.SELECT_AREA_NONE) {
return;
}
CPDFEditArea editArea = readerView.getSelectEditArea();
}
});
});Fullscreen Toggle Callback
documentFragment.setFillScreenChangeListener(fillScreen -> {
});For more callback interfaces, please refer to CPDFDocumentFragment, CPDFViewCtrl, and CPDFReaderView.