You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Flutter Text Selection Controls弃用,如何用contextMenuBuilder实现自定义选中文本工具栏?

替换弃用的MaterialTextSelectionControls,用contextMenuBuilder实现自定义文本选择工具栏

Flutter 中MaterialTextSelectionControls已被标记为弃用,官方推荐使用contextMenuBuilder来实现自定义文本选择菜单。以下是替代原有方案,在选中文本的默认工具栏旁添加「打开地图」按钮的完整实现:

核心实现逻辑

  • 给SelectableRegion设置contextMenuBuilder参数,替代原有的selectionControls
  • 复用默认文本选择菜单项,插入自定义的「打开地图」按钮
  • 处理自定义按钮点击逻辑,获取选中文本并触发地图打开操作

完整代码示例

SelectableRegion(
  contextMenuBuilder: (context, selectableRegionState) {
    // 获取当前选中的文本内容
    final selectedText = selectableRegionState.selectedText ?? '';
    
    return AdaptiveTextSelectionToolbar(
      anchors: selectableRegionState.contextMenuAnchors,
      children: [
        // 保留默认的复制/剪切/粘贴/全选功能按钮
        if (selectableRegionState.canCopy)
          TextSelectionToolbarTextButton(
            onPressed: () {
              selectableRegionState.copySelection(SelectionChangedCause.toolbar);
              selectableRegionState.hideContextMenu();
            },
            child: const Text('复制'),
          ),
        if (selectableRegionState.canCut)
          TextSelectionToolbarTextButton(
            onPressed: () {
              selectableRegionState.cutSelection(SelectionChangedCause.toolbar);
              selectableRegionState.hideContextMenu();
            },
            child: const Text('剪切'),
          ),
        if (selectableRegionState.canPaste)
          TextSelectionToolbarTextButton(
            onPressed: () async {
              await selectableRegionState.pasteText(SelectionChangedCause.toolbar);
              selectableRegionState.hideContextMenu();
            },
            child: const Text('粘贴'),
          ),
        if (selectableRegionState.canSelectAll)
          TextSelectionToolbarTextButton(
            onPressed: () {
              selectableRegionState.selectAll(SelectionChangedCause.toolbar);
              selectableRegionState.hideContextMenu();
            },
            child: const Text('全选'),
          ),
        // 添加自定义「打开地图」按钮
        if (selectedText.isNotEmpty)
          TextSelectionToolbarTextButton(
            onPressed: () {
              // 调用你的地图打开逻辑
              openLink(generateLocationLinkFromQuery(selectedText));
              selectableRegionState.hideContextMenu();
            },
            child: const Text('打开地图'),
          ),
      ],
    );
  },
  focusNode: _selectableRegionFocusNode,
  // 保留原有其他参数
  child: const Text('这里是可选中的文本内容,比如地址:北京市朝阳区'),
)

关键细节说明

  1. 选中文本获取:通过selectableRegionState.selectedText直接获取选中内容,无需旧方案中的delegate
  2. 默认菜单复用:利用selectableRegionState提供的canCopy、canCut等状态判断,保留原有功能
  3. 菜单位置适配:使用selectableRegionState.contextMenuAnchors确保菜单显示位置与默认行为一致
  4. 菜单关闭逻辑:点击按钮后调用selectableRegionState.hideContextMenu(),替代旧方案的delegate.hideToolbar()

如果需要贴合Material设计风格,也可以基于MaterialTextSelectionContextMenu实现,减少重复代码:

contextMenuBuilder: (context, selectableRegionState) {
  final selectedText = selectableRegionState.selectedText ?? '';
  return MaterialTextSelectionContextMenu(
    selectableRegionState: selectableRegionState,
    children: [
      // 复用Material默认的文本选择按钮
      ...MaterialTextSelectionContextMenu.buttonItems(
        context: context,
        selectableRegionState: selectableRegionState,
      ).map((item) => TextSelectionToolbarTextButton(
            onPressed: item.onPressed,
            child: Text(item.label),
          )),
      // 插入自定义按钮
      if (selectedText.isNotEmpty)
        TextSelectionToolbarTextButton(
          onPressed: () {
            openLink(generateLocationLinkFromQuery(selectedText));
            selectableRegionState.hideContextMenu();
          },
          child: const Text('打开地图'),
        ),
    ],
  );
},

内容的提问来源于stack exchange,提问作者user123

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.26 16:32:45