在Flutter中,有没有一种简单的方法来“链接”可能包含纯文本、电子邮件和web URL的文本?例如,如果我的文本是My phone number is 099 123 45 67 and my email is test@test.com
,则电话号码和电子邮件将被呈现为可点击的链接。
在Android中,它会是一行代码:
textView.setAutoLinkMask(Linkify.ALL);
我已经看到一个类似的问题被问到了here。这种解决方案对静态文本很有效,但对于动态文本,解析文本、检测所有URL、电话号码、电子邮件等并使用TextSpan
进行相应的渲染会复杂得多。
发布于 2018-09-19 07:04:45
我为此创建了一个新的包:flutter_linkify。目前仅支持URLS,但您可以随时在有功能请求的GitHub上提交问题。
Baisc用法:
import 'package:flutter_linkify/flutter_linkify.dart';
Linkify(
onOpen: (url) => print("Clicked $url!"),
text: "Made by https://cretezy.com",
);
发布于 2019-10-13 16:21:40
下面是我如何实现它的--使用buildTextWithLinks
函数来获得一个带有链接的Text
组件。
它使用url_launcher,目前支持网址,邮件和电话链接,但可以很容易地通过添加更多的RegExp
和处理器进行扩展。
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;
}
发布于 2018-12-04 21:21:25
感谢@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!');
})
])),
),
),
),
);
}
}
结果如下所示
https://stackoverflow.com/questions/51985111
复制相似问题