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

如何在Flutter的extended_text_field库中集成WidgetSpan?求示例

在ExtendedTextField中集成WidgetSpan(以EmailText为例)

1. 添加依赖

先确保pubspec.yaml中引入extended_text_field:

dependencies:
  flutter:
    sdk: flutter
  extended_text_field: ^latest_version # 替换为当前最新版本

2. 定义EmailText组件

实现自定义的邮箱样式组件(可根据需求调整交互和样式):

class EmailText extends StatelessWidget {
  final String email;
  final VoidCallback? onTap;

  const EmailText({super.key, required this.email, this.onTap});

  @override
  Widget build(BuildContext context) {
    return GestureDetector(
      onTap: onTap,
      child: Text(
        email,
        style: const TextStyle(
          color: Colors.blue,
          decoration: TextDecoration.underline,
        ),
      ),
    );
  }
}

3. 自定义SpecialTextSpanBuilder

这是核心逻辑,负责识别文本中的邮箱并替换为WidgetSpan包裹的EmailText:

class EmailSpecialTextSpanBuilder extends SpecialTextSpanBuilder {
  // 正则匹配邮箱格式
  static final RegExp _emailRegex = RegExp(
      r'[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}');

  @override
  SpecialText? createSpecialText(String flag,
      {TextStyle? textStyle, SpecialTextGestureTapCallback? onTap, int? index}) {
    return null;
  }

  @override
  InlineSpan build(String data, {TextStyle? textStyle, onTap}) {
    final spans = <InlineSpan>[];
    int currentIndex = 0;

    // 全局扫描文本中的邮箱
    Iterable<Match> matches = _emailRegex.allMatches(data);
    for (Match match in matches) {
      // 添加邮箱之前的普通文本
      if (match.start > currentIndex) {
        spans.add(TextSpan(
          text: data.substring(currentIndex, match.start),
          style: textStyle,
        ));
      }
      // 添加邮箱对应的WidgetSpan
      spans.add(WidgetSpan(
        child: EmailText(
          email: match.group(0)!,
          onTap: () {
            debugPrint('点击邮箱:${match.group(0)}');
            // 可扩展逻辑:比如唤起邮箱应用、复制邮箱等
          },
        ),
      ));
      currentIndex = match.end;
    }

    // 添加剩余的普通文本
    if (currentIndex < data.length) {
      spans.add(TextSpan(
        text: data.substring(currentIndex),
        style: textStyle,
      ));
    }

    return TextSpan(children: spans);
  }
}

4. 在ExtendedTextField中集成

将自定义的Builder配置到输入框中:

class EmailTextFieldPage extends StatefulWidget {
  const EmailTextFieldPage({super.key});

  @override
  State<EmailTextFieldPage> createState() => _EmailTextFieldPageState();
}

class _EmailTextFieldPageState extends State<EmailTextFieldPage> {
  final TextEditingController _controller = TextEditingController();

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: const Text('带邮箱组件的输入框')),
      body: Padding(
        padding: const EdgeInsets.all(16.0),
        child: ExtendedTextField(
          controller: _controller,
          specialTextSpanBuilder: EmailSpecialTextSpanBuilder(),
          decoration: const InputDecoration(
            hintText: '输入包含邮箱的内容',
            border: OutlineInputBorder(),
          ),
          maxLines: null,
        ),
      ),
    );
  }

  @override
  void dispose() {
    _controller.dispose();
    super.dispose();
  }
}

// 启动示例
void main() {
  runApp(const MaterialApp(home: EmailTextFieldPage()));
}

关键说明

  • 自定义SpecialTextSpanBuilder会实时解析输入文本,将匹配到的邮箱自动替换为EmailText组件
  • 若需要调整邮箱匹配规则,直接修改正则表达式即可
  • WidgetSpan支持包裹任意Widget,可根据需求扩展EmailText的样式(比如添加头像、标记)或交互逻辑

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.06 10:30:45