Skip to content
ComPDF
Guides

自定义菜单

在查看 PDF 时,当用户选择文本或在空白区域长按时,PDF 会进入相应的交互状态。此时,系统会弹出上下文菜单(Context Menu),用于执行与当前交互状态相关的操作。

通过继承 CPDFContextMenuShowHelper 并重写对应方法,您可以自定义菜单布局、内容和交互行为。例如,高亮注释的上下文菜单可以包含“属性修改”、“复制文本”、“删除注释”等操作。

操作流程示意

tsx
用户操作

   │ 选择文本 / 空白区域长按

PDF 进入相应交互状态

   │ 弹出上下文菜单

自定义菜单项点击

   │ 执行对应操作(修改属性 / 复制文本 / 删除注释等)

刷新 PDF 页面 / 更新界面

示意图(高亮注释为例):

tex
+---------------------+
|  高亮注释           |
|  Lorem ipsum...     |
+---------------------+

        ▼  长按 / 点击菜单
+---------------------+
| 属性 | 复制 | 删除   |   <- 自定义上下文菜单
+---------------------+

示例:高亮注释自定义菜单

t_markup_annot_menu_layout.xml:

xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:background="@drawable/bg_context_menu_window"
    android:orientation="horizontal">

    <TextView
        android:id="@+id/attr"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="属性" />

    <TextView
        android:id="@+id/copy"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="复制" />

    <TextView
        android:id="@+id/delete"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="删除" />

</LinearLayout>
java

public class TContextMenuHelper extends CPDFContextMenuShowHelper {
    @Override
    public View getMarkupContentView(CPDFPageView pageView, CPDFBaseAnnotImpl annotImpl, LayoutInflater layoutInflater) {
        View contentView = layoutInflater.inflate(R.layout.t_markup_annot_menu_layout, null);
        CPDFMarkupAnnotImpl markupAnnotImpl = (CPDFMarkupAnnotImpl) annotImpl;
        CPDFMarkupAnnotation markupAnnotation = markupAnnotImpl.onGetAnnotation();

        // 设置菜单点击事件
        invokeOnClickListener(contentView, v -> {
            int id = v.getId();
            if (id == R.id.attr) {  // 修改属性
                markupAnnotation.setColor(Color.RED);
                markupAnnotation.setAlpha(100);
                markupAnnotation.updateAp();
                markupAnnotImpl.onAnnotAttrChange();
                pageView.invalidate();
            } else if (id == R.id.copy) { // 复制文本
                String markedText = markupAnnotation.getMarkedText();
                if (!TextUtils.isEmpty(markedText)) {
                    CPDFTextUtils.setClipData(context, "ComPDF", markedText);
                }
            } else if (id == R.id.delete) { // 删除注释
                pageView.deleteAnnotation(annotImpl);
            }
            popupWindow.dismiss();
        }, R.id.attr, R.id.copy, R.id.delete);

        return contentView;
    }
}
kotlin
class TContextMenuHelper(readerView: CPDFReaderView?) : CPDFContextMenuShowHelper(readerView) {
    override fun getMarkupContentView(
        pageView: CPDFPageView,
        annotImpl: CPDFBaseAnnotImpl<*>,
        layoutInflater: LayoutInflater
    ): View {
        val contentView = layoutInflater.inflate(R.layout.t_markup_annot_menu_layout, null)
        val markupAnnotImpl = annotImpl as CPDFMarkupAnnotImpl
        val markupAnnotation = markupAnnotImpl.onGetAnnotation()

        // 设置菜单点击事件
        invokeOnClickListener(contentView, { v ->
            when (v.id) {
                R.id.attr -> { // 修改属性
                    markupAnnotation.color = Color.RED
                    markupAnnotation.alpha = 100
                    markupAnnotation.updateAp()
                    markupAnnotImpl.onAnnotAttrChange()
                    pageView.invalidate()
                }
                R.id.copy -> { // 复制文本
                    val markedText = markupAnnotation.markedText
                    if (markedText.isNotEmpty()) {
                        CPDFTextUtils.setClipData(context, "ComPDF", markedText)
                    }
                }
                R.id.delete -> { // 删除注释
                    pageView.deleteAnnotation(annotImpl)
                }
            }
            popupWindow.dismiss()
        }, R.id.attr, R.id.copy, R.id.delete)

        return contentView
    }
}

设置 CPDFReaderView 使用自定义上下文菜单:

java
getCPdfReaderView().setContextMenuShowListener(new TContextMenuHelper(readerView));

可自定义上下文菜单方法列表

方法名适用注释/操作类型说明
getShapeContentView图形注释自定义图形类注释的上下文菜单
getFreetextContentView自由文本注释自由文本注释的上下文菜单
getMarkupContentView高亮/下划线/波浪线注释标记类注释的上下文菜单
getInkContentView手绘/签名注释手绘注释的上下文菜单
getStampContentView印章注释印章注释的上下文菜单
getLinkContentView链接注释链接注释的上下文菜单
getNoteContentView批注/便签便签注释的上下文菜单
getSoundContentView音频注释音频注释的上下文菜单
getCheckboxContentView表单-复选框复选框表单的上下文菜单
getComboboxContentView表单-下拉框下拉框表单的上下文菜单
getListboxContentView表单-列表框列表框表单的上下文菜单
getPushbuttonContentView表单-按钮按钮表单的上下文菜单
getRadiobuttonContentView表单-单选按钮单选按钮表单的上下文菜单
getSignatureContentView数字签名签名区域上下文菜单
getTextfieldContentView表单-文本框文本框表单上下文菜单
getSelectTextContentView文字选择选中文字的上下文菜单
getEditImageAreaContentView图片编辑区域编辑图片区域的上下文菜单
getLongPressContentView空白区域长按空白区域长按菜单
getEditLongPressContentView编辑模式长按编辑模式下长按菜单
getEditTextAreaContentView文本区域编辑文本编辑区域菜单
getEditSelectTextContentView编辑模式选中文本文本选择菜单
getEditTextContentView编辑文本文本编辑菜单
getRedactContentView涂黑/隐藏内容涂黑操作菜单
getCropImageAreaContentView图片裁剪裁剪图片区域菜单
getSearchReplaceContentView查找/替换查找替换菜单
getEditPathAreaContentView路径编辑路径编辑菜单
getScreenShotContentView截图区域截图操作菜单

说明:表格中列出的所有方法均可通过继承 CPDFContextMenuShowHelper 并重写实现自定义菜单。不同方法对应不同注释类型或操作类型,开发者可根据需求重写菜单布局和行为。