[英]How to create a hyperlink in Flutter widget?
我想創建一個超鏈接以顯示在我的 Flutter 應用程序中。
超鏈接應嵌入Text
或類似的文本視圖中,例如:
The last book bought is <a href='#'>this</a>
有什么提示嗎?
只需在 Text 小部件周圍包裹一個 InkWell,並為 onTap 屬性提供一個 UrlLauncher(來自服務庫)。 在下面使用之前,將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('UrlLauchner'),
),
body: new Center(
child: new InkWell(
child: new Text('Open Browser'),
onTap: () => launch('https://docs.flutter.io/flutter/services/UrlLauncher-class.html')
),
),
),
);
}
}
您可以為 Text 小部件提供樣式,使其看起來像一個鏈接。
在稍微調查了這個問題后,我找到了一個不同的解決方案來實現您要求的“內嵌”超鏈接。 您可以將RichText Widget與封閉的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');
},
),
],
),
),
),
),
);
}
}
通過這種方式,您實際上可以突出顯示一個單詞並從中創建一個超鏈接;)
Flutter 沒有內置的超鏈接支持,但你可以自己偽造它。 Gallery 的 drawer.dart 中有一個例子。 他們使用包含彩色TextSpan
的RichText
小部件,該小部件具有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,
),
],
),
您可以使用包 flutter_linkify
https://pub.dev/packages/flutter_linkify
只是想提供另一種選擇。
包將分割您的文本並自動突出顯示 http/https
結合插件 url_launcher 你可以啟動 url
您可以查看以下示例:
完整代碼如下
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 2.0 中,引入了 Link 小部件。 使用此小部件可啟動網頁並導航到應用程序中的新屏幕。 在使用之前,您需要使用 url_launcher 包。
url_launcher: ^6.0.8
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,
),
),
);
},
),
如果您想擁有更高級的文本功能,可以使用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 中。
在您的應用程序中放置可點擊鏈接的另一種(或不)方法(對我來說它就是這樣工作的):
1 - 在 pubspec.yaml 文件中添加 url_launcher 包
(包版本 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';
}
}
}
這是一個交鑰匙 package https://pub.dev/packages/link_text
child: LinkText(
'Hello check http://google.com',
textStyle: ...,
),
為這種復雜性使用庫更安全
優點:
建議將
RichText<\/code>與
TextSpan<\/code> +
GestureRecognizer<\/code>一起使用的問題的答案在功能上都是正確的,但從 UX 的角度來看,它們不會向響應觸摸的用戶提供反饋。
為了保持與其他 Material 小部件的一致性,您可以使用類似的方法,但改用
WidgetSpan<\/code> +
InkWell<\/code> 。
此示例使用url_launcher<\/a>包和無樣式的 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';
}
}
}
添加一個更簡單整潔的技巧,因為上述技巧對於某些用例來說過於復雜。 我使用 RichText - WidgetSpan、TextButton 和 URL 啟動器 package 完成了它。 只需根據您的需要修改以下示例塊。
代碼:
class UserAgreementText extends StatelessWidget {
const UserAgreementText({Key? key}) : super(key: key);
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 Row(
children: [
Expanded(
child: RichText(
textAlign: TextAlign.center,
text: TextSpan(
text: 'By logging in, you accept our ',
style: Theme.of(context).textTheme.bodySmall,
children: <InlineSpan>[
WidgetSpan(
alignment: PlaceholderAlignment.baseline,
baseline: TextBaseline.alphabetic,
child: 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(
"https://example.com/terms-and-conditions");
},
child: const Text("Terms and Conditions"),
),
),
const TextSpan(
text: ' and ',
),
WidgetSpan(
alignment: PlaceholderAlignment.baseline,
baseline: TextBaseline.alphabetic,
child: 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(
"https://example.com/privacy-policy");
},
child: const Text("Privacy Policy"),
),
),
],
),
),
),
],
);
}
}
這可能會晚了; 但是我發現了這個包裹
https://github.com/Sub6Resources/flutter_html
結合網址啟動器https://pub.dev/packages/url_launcher
可以在水龍頭上為我們提供很棒的html鏈接,例如widget(包括html href)
Html(
data: """
<!--For a much more extensive example, look at example/main.dart-->
<div>
<h1>Demo Page</h1>
<p>This is a fantastic nonexistent product that you should buy!</p>
<h2>Pricing</h2>
<p>Lorem ipsum <b>dolor</b> sit amet.</p>
<h2>The Team</h2>
<p>There isn't <i>really</i> a team...</p>
<h2>Installation</h2>
<p>You <u>cannot</u> install a nonexistent product!</p>
<!--You can pretty much put any html in here!-->
</div>
""",
//Optional parameters:
padding: EdgeInsets.all(8.0),
backgroundColor: Colors.white70,
defaultTextStyle: TextStyle(fontFamily: 'serif'),
linkStyle: const TextStyle(
color: Colors.redAccent,
),
onLinkTap: (url) {
// open url in a webview
},
onImageTap: (src) {
// Display the image in large form.
},
//Must have useRichText set to false for this to work.
customRender: (node, children) {
if(node is dom.Element) {
switch(node.localName) {
case "video": return Chewie(...);
case "custom_tag": return CustomWidget(...);
}
}
},
customTextAlign: (dom.Node node) {
if (node is dom.Element) {
switch (node.localName) {
case "p":
return TextAlign.justify;
}
}
},
customTextStyle: (dom.Node node, TextStyle baseStyle) {
if (node is dom.Element) {
switch (node.localName) {
case "p":
return baseStyle.merge(TextStyle(height: 2, fontSize: 20));
}
}
return baseStyle;
},
)
所有學分都歸授給導師。
干杯。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.