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

如何在Flutter中实现Android风格的文本选中操作选项?

在Flutter中实现Android原生文本选中操作菜单

Flutter自带的Text、SelectableText和TextField组件无法直接调用Android系统级的文本操作菜单(包含全选、复制、剪切、翻译、分享及第三方词典等选项),要实现这个功能,需要通过平台通道(Platform Channel) 结合Android原生代码来打通Flutter与系统文本操作的交互。

实现步骤

1. Flutter端:监听文本选中并调用原生方法

基于SelectableText组件改造,监听文本选中事件,获取选中内容后通过平台通道传递给Android端,触发系统操作菜单。

import 'package:flutter/material.dart';
import 'package:flutter/services.dart';

class NativeSelectableText extends StatefulWidget {
  final String text;
  final TextStyle? style;

  const NativeSelectableText({
    super.key,
    required this.text,
    this.style,
  });

  @override
  State<NativeSelectableText> createState() => _NativeSelectableTextState();
}

class _NativeSelectableTextState extends State<NativeSelectableText> {
  static const _channel = MethodChannel('your.package.name/text_action_menu');
  String? _selectedContent;

  @override
  Widget build(BuildContext context) {
    return SelectableText(
      widget.text,
      style: widget.style,
      onSelectionChanged: (selection, cause) {
        // 仅当选中有效文本时触发
        if (selection.isValid && selection.start != selection.end) {
          final content = widget.text.substring(selection.start, selection.end);
          setState(() => _selectedContent = content);
          _triggerNativeMenu(content);
        }
      },
    );
  }

  Future<void> _triggerNativeMenu(String text) async {
    try {
      await _channel.invokeMethod('showSystemActionMenu', {'selectedText': text});
    } on PlatformException catch (e) {
      debugPrint("调用原生菜单失败: ${e.message}");
    }
  }
}

// 使用示例
void main() => runApp(const MaterialApp(
      home: Scaffold(
        body: Padding(
          padding: EdgeInsets.all(16),
          child: NativeSelectableText(
            text: "测试文本:选中这段内容,即可唤起Android原生操作菜单,包含全选、复制、翻译、分享等系统及第三方应用选项",
            style: TextStyle(fontSize: 16),
          ),
        ),
      ),
    ));

2. Android原生端:实现系统操作菜单

在MainActivity中注册平台通道,接收Flutter传递的选中文本,通过ActionMode唤起系统原生文本操作菜单,系统会自动整合第三方应用提供的操作选项(如翻译、词典)。

import android.view.ActionMode
import android.view.Menu
import android.view.MenuItem
import io.flutter.embedding.android.FlutterActivity
import io.flutter.embedding.engine.FlutterEngine
import io.flutter.plugin.common.MethodChannel

class MainActivity : FlutterActivity() {
    private val CHANNEL = "your.package.name/text_action_menu"
    private var selectedText: String? = null
    private var actionMode: ActionMode? = null

    override fun configureFlutterEngine(flutterEngine: FlutterEngine) {
        super.configureFlutterEngine(flutterEngine)
        MethodChannel(flutterEngine.dartExecutor.binaryMessenger, CHANNEL).setMethodCallHandler { call, result ->
            when (call.method) {
                "showSystemActionMenu" -> {
                    selectedText = call.argument<String>("selectedText")
                    // 启动系统ActionMode
                    actionMode = startActionMode(actionModeCallback)
                    result.success(null)
                }
                else -> result.notImplemented()
            }
        }
    }

    private val actionModeCallback = object : ActionMode.Callback {
        override fun onCreateActionMode(mode: ActionMode?, menu: Menu?): Boolean {
            // 加载系统默认文本操作菜单
            mode?.menuInflater?.inflate(android.R.menu.select_all_menu, menu)
            return true
        }

        override fun onPrepareActionMode(mode: ActionMode?, menu: Menu?): Boolean {
            mode?.title = "文本操作"
            return true
        }

        override fun onActionItemClicked(mode: ActionMode?, item: MenuItem?): Boolean {
            return when (item?.itemId) {
                android.R.id.selectAll -> {
                    // 如需通知Flutter全选文本,可通过通道回调实现
                    mode?.finish()
                    true
                }
                android.R.id.copy -> {
                    val clipboard = getSystemService(CLIPBOARD_SERVICE) as android.content.ClipboardManager
                    val clipData = android.content.ClipData.newPlainText("Selected Text", selectedText)
                    clipboard.setPrimaryClip(clipData)
                    mode?.finish()
                    true
                }
                android.R.id.cut -> {
                    // 剪切功能需结合Flutter端文本编辑逻辑,通过通道同步修改
                    mode?.finish()
                    true
                }
                else -> false // 交由系统处理第三方应用的操作选项
            }
        }

        override fun onDestroyActionMode(mode: ActionMode?) {
            actionMode = null
            selectedText = null
        }
    }
}

关键注意事项

  • 通道名称一致性:Flutter和Android端的通道名称必须完全匹配(示例中为your.package.name/text_action_menu),请替换为自己项目的包名。
  • 剪切功能适配:如果需要支持剪切,需在Flutter端实现文本可编辑逻辑,并通过平台通道将文本修改需求同步到原生端。
  • 第三方选项整合:Android系统会自动识别已安装的支持文本操作的应用(如翻译APP、词典),并将其选项添加到操作菜单中,无需额外代码开发。
  • 可编辑文本场景:如果是输入框场景,也可以通过Platform View将原生EditText嵌入Flutter,直接使用原生文本选择菜单,但会增加少量性能开销。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.23 15:05:12