如何在颤振小部件中创建超链接?

我想创建一个超链接显示在我的扑动应用程序。

超链接应该嵌入到Text或类似的文本视图中,例如:

The last book bought is <a href='#'>this</a>

有什么提示吗?

205348 次浏览

Flutter没有内置的超链接支持,但您可以自己伪造它。在画廊drawer.dart中有一个例子。它们使用一个包含彩色TextSpanRichText小部件,它有一个recognizer属性来处理点击:

        RichText(
text: TextSpan(
children: [
TextSpan(
style: bodyTextStyle,
text: seeSourceFirst,
),
TextSpan(
style: bodyTextStyle.copyWith(
color: colorScheme.primary,
),
text: repoText,
recognizer: TapGestureRecognizer()
..onTap = () async {
final url = 'https://github.com/flutter/gallery/';
if (await canLaunch(url)) {
await launch(
url,
forceSafariVC: false,
);
}
},
),
TextSpan(
style: bodyTextStyle,
text: seeSourceSecond,
),
],
),

enter image description here

enter image description here

只需将InkWell包装在Text小部件周围,并将UrlLauncher(来自服务库)提供给onTap属性。在下面使用它之前,将UrlLauncher安装为Flutter包。

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




void main() {
runApp(new MyApp());
}


class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return new MaterialApp(
home: new Scaffold(
appBar: new AppBar(
title: new Text('UrlLauncher'),
),
body: new Center(
child: new InkWell(
child: new Text('Open Browser'),
onTap: () => launch('https://docs.flutter.io/flutter/services/UrlLauncher-class.html')
),
),
),
);
}
}

您可以为Text小部件提供一个样式,使其看起来像一个链接。

更新

在研究了这个问题之后,我发现了一个不同的解决方案来实现你所要求的“在线”超链接。你可以将RichText小部件和附带的TextSpans一起使用。

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


void main() {
runApp(new MyApp());
}


class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return new MaterialApp(
home: new Scaffold(
appBar: new AppBar(
title: new Text('UrlLauchner'),
),
body: new Center(
child: new RichText(
text: new TextSpan(
children: [
new TextSpan(
text: 'This is no Link, ',
style: new TextStyle(color: Colors.black),
),
new TextSpan(
text: 'but this is',
style: new TextStyle(color: Colors.blue),
recognizer: new TapGestureRecognizer()
..onTap = () { launch('https://docs.flutter.io/flutter/services/UrlLauncher-class.html');
},
),
],
),
),
),
),
);
}
}

这样你就可以突出显示一个单词,并从中创建一个超链接;)

如果你想让它看起来更像一个链接,你可以添加下划线:

new Text("Hello Flutter!", style: new TextStyle(color: Colors.blue, decoration: TextDecoration.underline),)

结果是:

enter image description here

更新(Android >= 11):

  • < h4 > iOS配置:

    打开info.plist文件并添加:

    <key>LSApplicationQueriesSchemes</key>
    <array>
    <string>https</string>
    </array>
    
  • < h4 >安卓系统配置:

    打开位于app/src/main中的AndroidManifest.xml文件,并在根目录添加以下内容:

    <manifest xmlns:android="http://schemas.android.com/apk/res/android">
    
    
    <!-- Add this query -->
    <queries>
    <intent>
    <action android:name="android.intent.action.VIEW" />
    <data android:scheme="https" />
    </intent>
    </queries>
    
    
    <application ... />
    
    
    </manifest>
    

颤振代码:

简单地将你的Text包装在GestureDetectorInkWell中,并使用url_launcher包在onTap()中处理单击。

InkWell(
onTap: () => launchUrl(Uri.parse('https://www.google.com')),
child: Text(
'Click here',
style: TextStyle(decoration: TextDecoration.underline, color: Colors.blue),
),
)

截图:

enter image description here

在应用中添加可点击链接的另一种(或不是)方法 (对我来说就是这样):

1 -在你的pubspec中添加url_launcher包。yaml文件

(包版本5.0对我来说不太好,所以我使用4.2.0+3)。

dependencies:
flutter:
sdk: flutter
url_launcher: ^4.2.0+3

2 -导入并使用如下。

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


void main() {
runApp(MaterialApp(
title: 'Navigation Basics',
home: MyUrl(),
));
}


class MyUrl extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Url Launcher'),
),
body: Center(
child: FlatButton(
onPressed: _launchURL,
child: Text('Launch Google!',
style: TextStyle(fontSize: 17.0)),
),
),
);
}


_launchURL() async {
const url = 'https://google.com.br';
if (await canLaunch(url)) {
await launch(url);
} else {
throw 'Could not launch $url';
}
}
}

可以使用flutter_linkify
https://pub.dev/packages/flutter_linkify < br > 只是想提供另一种选择。< br > 包将区分文本并自动突出显示http/https
结合插件url_launcher,你可以启动url
你可以查看下面的例子:

enter image description here

完整代码如下

import 'package:flutter/material.dart';
import 'package:flutter_linkify/flutter_linkify.dart';
import 'dart:async';


import 'package:url_launcher/url_launcher.dart';


void main() => runApp(new LinkifyExample());


class LinkifyExample extends StatelessWidget {
@override
Widget build(BuildContext context) {
return new MaterialApp(
title: 'flutter_linkify example',
home: Scaffold(
appBar: AppBar(
title: Text('flutter_linkify example'),
),
body: Center(
child: Linkify(
onOpen: _onOpen,
text: "Made by https://cretezy.com \n\nMail: example@gmail.com \n\n  this is test http://pub.dev/ ",
),
),
),
);
}


Future<void> _onOpen(LinkableElement link) async {
if (await canLaunch(link.url)) {
await launch(link.url);
} else {
throw 'Could not launch $link';
}
}
}

你可以使用链接文本https://pub.dev/packages/link_text 然后像

那样使用它
 final String _text = 'Lorem ipsum https://flutter.dev\nhttps://pub.dev';
@override
Widget build(BuildContext context) {
return Scaffold(
body: Center(
child: LinkText(
text: _text,
textAlign: TextAlign.center,
),
),
);
}

flutter link widget

在Flutter 2.0中,引入了Link小部件。使用这个小部件来启动网页,也可以导航到应用程序中的新屏幕。在使用它之前,你需要使用url_launcher包。

url_launcher: ^6.0.8

For More Information

Link(
uri: Uri.parse('https://androidride.com'),
//target: LinkTarget.self,
builder: (context, followLink) {
return RichText(
text: TextSpan(children: [
TextSpan(
text: 'Click here: ',
style: TextStyle(
fontSize: 20,
color: Colors.black,
),
),
TextSpan(
text: 'AndroidRide',
style: TextStyle(
color: Colors.blue,
decoration: TextDecoration.underline,
fontWeight: FontWeight.bold,
fontSize: 21,
),
recognizer: TapGestureRecognizer()
..onTap = followLink,
),
]),
);
}),
),
SizedBox(
height: 20,
),
Link(
uri: Uri.parse('/second'),
builder: (context, followLink) {
return InkWell(
onTap: followLink,
child: Text(
'Go to Second Screen',
style: TextStyle(
fontSize: 20,
color: Colors.blue,
decoration: TextDecoration.underline,
),
),
);
},
),

这个问题的答案建议使用RichTextTextSpan + GestureRecognizer在功能上都是正确的,但从用户体验的角度来看,他们没有为响应触摸的用户提供反馈。为了保持与其他Material小部件的一致性,你可以使用类似的方法,但是使用WidgetSpan + InkWell

这个例子使用了url_launcher包和一个非样式的InkWell,但是你可以自定义你认为合适的:

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


class TextWithLink extends StatelessWidget {
const TextWithLink({Key? key}) : super(key: key);


@override
Widget build(BuildContext context) {
const textStyle = TextStyle(color: Colors.black); // default style for all text
return RichText(
text: TextSpan(
style: textStyle,
children: [
const TextSpan(
text: 'The last book bought is ',
),
WidgetSpan(
alignment: PlaceholderAlignment.middle,
child: InkWell(
onTap: () => _launchUrl('https://url-to-launch.com'),
child: Text('this',
style: textStyle.merge(const TextStyle(
color: Colors.blue, fontWeight: FontWeight.bold))))), // override default text styles with link-specific styles
],
),
);
}


_launchUrl(String url) async {
if (await canLaunch(url)) {
await launch(url);
} else {
throw 'Could not launch $url';
}
}
}

如果你想拥有更高级的文本功能,你可以使用flutter_html插件:

Html(
data: 'The last <i><u><b>book</b></u></i> bought is <a href="#">this</a>',
onLinkTap: (url, context, attrs, element) {
// Handle link tapped...
},
)

这只是这个插件功能的冰山一角。

只是一个想法:你甚至可以把你的flutter应用程序的一部分作为html在线托管,并使用这个插件将它们渲染为flutter中的小部件。

这是一个交钥匙包 https://pub.dev/packages/link_text < / p >
child: LinkText(
'Hello check http://google.com',
textStyle: ...,
),

对于这种复杂性,使用库更安全

优点:

  • 作为单个参数接受整个字符串
  • 解析链接并将其呈现为可点击的UI,与不可点击的文本内联
  • 不需要复杂的RichText结构

再添加一个简单而整洁的技巧,因为上面的技巧对于某些用例来说过于复杂。我用RichText - WidgetSpan, TextButton和URL启动包。只需根据您的需要修改下面的示例块。

结果:Result

代码:

class UserAgreementText extends StatelessWidget {
const UserAgreementText({Key? key}) : super(key: key);


@override
Widget build(BuildContext context) {
return Row(
children: [
Expanded(
child: RichText(
textAlign: TextAlign.center,
text: TextSpan(
text: 'By logging in, you accept our ',
style: Theme.of(context).textTheme.bodySmall,
children: const <InlineSpan>[
WidgetSpan(
alignment: PlaceholderAlignment.baseline,
baseline: TextBaseline.alphabetic,
child: LinkButton(
urlLabel: "Terms and Conditions",
url: "https://example.com/terms-and-conditions"),
),
TextSpan(
text: ' and ',
),
WidgetSpan(
alignment: PlaceholderAlignment.baseline,
baseline: TextBaseline.alphabetic,
child: LinkButton(
urlLabel: "Privacy Policy",
url: "https://example.com/privacy-policy"),
),
],
),
),
),
],
);
}
}

link_button.dart

class LinkButton extends StatelessWidget {
const LinkButton({Key? key, required this.urlLabel, required this.url})
: super(key: key);


final String urlLabel;
final String url;


Future<void> _launchUrl(String url) async {
final Uri uri = Uri.parse(url);


if (!await launchUrl(uri)) {
throw 'Could not launch $uri';
}
}


@override
Widget build(BuildContext context) {
return TextButton(
style: TextButton.styleFrom(
padding: EdgeInsets.zero,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(0),
),
tapTargetSize: MaterialTapTargetSize.shrinkWrap,
visualDensity: VisualDensity.compact,
minimumSize: const Size(0, 0),
textStyle: Theme.of(context).textTheme.bodySmall,
),
onPressed: () {
_launchUrl(url);
},
child: Text(urlLabel),
);
}
}