如何在Flutter中链接文本

Ege*_*men 4 dart flutter

Flutter中是否有一种简单的方法可以“链接”包含纯文本,电子邮件和Web URL的文本?例如,如果我的文字是My phone number is 099 123 45 67 and my email is test@test.com电话号码,并且电子邮件将显示为可点击的链接。

在Android中,它将是一个衬里:

textView.setAutoLinkMask(Linkify.ALL);
Run Code Online (Sandbox Code Playgroud)

我已经看到在这里提出了类似的问题。该解决方案适用于静态文本,但对于动态文本,解析文本,检测所有URL,电话号码,电子邮件等,并使用TextSpans进行渲染会复杂得多。

小智 8

我为此创建了一个新包:flutter_linkify。它目前仅支持URLS,但是您始终可以通过功能请求在GitHub上提交问题。

Baisc用法:

import 'package:flutter_linkify/flutter_linkify.dart';

Linkify(
  onOpen: (url) => print("Clicked $url!"),
  text: "Made by https://cretezy.com",
);
Run Code Online (Sandbox Code Playgroud)

  • 添加打开系统应用程序、电子邮件、第三方应用程序、拨打电话号码的功能 (3认同)

Phu*_*ran 5

感谢@Charles Crete 创建该库。

我只想通过结合 RichText、TextSpan 和 TapGestureRecognizer(都在 Flutter 框架中)在这里添加一个解决方案

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

void main() {
  runApp(HyperLinkDemo());
}

class HyperLinkDemo extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
        body: Center(
          child: Padding(
            padding: const EdgeInsets.all(8.0),
            child: RichText(
                text: TextSpan(children: [
              TextSpan(
                  text: 'This is a very long text, but you can not click on it. ',
                  style: TextStyle(fontSize: 20, color: Colors.black)),
              TextSpan(
                  text: 'And this is a clickable text',
                  style: TextStyle(
                      fontSize: 20,
                      color: Colors.blue,
                      decoration: TextDecoration.underline),
                  recognizer: TapGestureRecognizer()
                    ..onTap = () {
                      print('You clicked on me!');
                    })
            ])),
          ),
        ),
      ),
    );
  }
}
Run Code Online (Sandbox Code Playgroud)

这是结果

在此处输入图片说明

  • 我相信OP正在询问自动检测电话号码、地址或链接的代码,而不仅仅是将某些文本硬编码为“可点击”。 (4认同)

spl*_*tor 5

这是我实现它的方式 - 使用该buildTextWithLinks函数获取Text带有链接的组件。

它使用 url_launcher 并且当前支持 URL、邮件和电话链接,但可以通过添加更多RegExps 和处理程序轻松扩展。

import 'package:url_launcher/url_launcher.dart';

Text buildTextWithLinks(String textToLink) => Text.rich(TextSpan(children: linkify(textToLink)));

Future<void> openUrl(String url) async {
  if (await canLaunch(url)) {
    await launch(url);
  } else {
    throw 'Could not launch $url';
  }
}

const String urlPattern = r'https?:/\/\\S+';
const String emailPattern = r'\S+@\S+';
const String phonePattern = r'[\d-]{9,}';
final RegExp linkRegExp = RegExp('($urlPattern)|($emailPattern)|($phonePattern)', caseSensitive: false);

WidgetSpan buildLinkComponent(String text, String linkToOpen) => WidgetSpan(
    child: InkWell(
      child: Text(
        text,
        style: TextStyle(
          color: Colors.blueAccent,
          decoration: TextDecoration.underline,
        ),
      ),
      onTap: () => openUrl(linkToOpen),
    )
);

List<InlineSpan> linkify(String text) {
  final List<InlineSpan> list = <InlineSpan>[];
  final RegExpMatch match = linkRegExp.firstMatch(text);
  if (match == null) {
    list.add(TextSpan(text: text));
    return list;
  }

  if (match.start > 0) {
    list.add(TextSpan(text: text.substring(0, match.start)));
  }

  final String linkText = match.group(0);
  if (linkText.contains(RegExp(urlPattern, caseSensitive: false))) {
    list.add(buildLinkComponent(linkText, linkText));
  }
  else if (linkText.contains(RegExp(emailPattern, caseSensitive: false))) {
    list.add(buildLinkComponent(linkText, 'mailto:$linkText'));
  }
  else if (linkText.contains(RegExp(phonePattern, caseSensitive: false))) {
    list.add(buildLinkComponent(linkText, 'tel:$linkText'));
  } else {
    throw 'Unexpected match: $linkText';
  }

  list.addAll(linkify(text.substring(match.start + linkText.length)));

  return list;
}
Run Code Online (Sandbox Code Playgroud)

  • 伟大的!感谢您的回答。你节省了我们的又一个依赖。这里只有一件事是 `urlPattern` 无法通过复制此代码来工作,尽管当我将其更改为 `const String urlPattern = 'https?:/\/\\S+';` 时它可以工作。 (2认同)

Wai*_* Ko 5

该功能可以自动检测文本视图中的超链接是什么。您可以根据您的要求修改\nRegx 模式。

\n
List<TextSpan> extractText(String rawString) {\nList<TextSpan> textSpan = [];\n\nfinal urlRegExp = new RegExp(\n    r"((https?:www\\.)|(https?:\\/\\/)|(www\\.))[-a-zA-Z0-9@:%._\\+~#=]{1,256}\\.[a-zA-Z0-9]{1,6}(\\/[-a-zA-Z0-9()@:%_\\+.~#?&\\/=]*)?");\n\ngetLink(String linkString) {\n  textSpan.add(\n    TextSpan(\n      text: linkString,\n      style: new TextStyle(color: Colors.blue),\n      recognizer: new TapGestureRecognizer()\n        ..onTap = () {\n          Fluttertoast.showToast(msg: linkString);\n        },\n    ),\n  );\n  return linkString;\n}\n\ngetNormalText(String normalText) {\n  textSpan.add(\n    TextSpan(\n      text: normalText,\n      style: new TextStyle(color: Colors.black),\n    ),\n  );\n  return normalText;\n}\n\nrawString.splitMapJoin(\n  urlRegExp,\n  onMatch: (m) => getLink("${m.group(0)}"),\n  onNonMatch: (n) => getNormalText("${n.substring(0)}"),\n);\n\nreturn textSpan;}\n
Run Code Online (Sandbox Code Playgroud)\n

用法

\n
child: SelectableText.rich(\n                TextSpan(\n                    children: extractText(dummyText),\n                    style: TextStyle(fontSize: _fontSize)),\n              )\n
Run Code Online (Sandbox Code Playgroud)\n

这是结果

\n

\xc2\xa0

\n