I would like to create a hyperlink to display in my Flutter app.
The hyper link should be embedded in a Text
or similar text views like:
The last book bought is <a href='#'>this</a>
Any hint to do this?
Just wrap an InkWell around a Text widget and supply an UrlLauncher (from the service library) to the onTap attribute. InstallUrlLauncher as a Flutter package before using it below.
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')
),
),
),
);
}
}
You can supply a style to the Text widget to make it look like a link.
After looking into the issue a little I found a different solution to implement the 'in line' hyperlinks you asked for. You can use the RichText Widget with enclosed 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');
},
),
],
),
),
),
),
);
}
}
This way you can actually highlight one word and make a hyperlink out of it ;)
Flutter doesn't have built-in hyperlink support but you can fake it yourself. There's an example in the Gallery's drawer.dart . They use a RichText
widget containing a coloured TextSpan
, which has a recognizer
attribute to handle taps:
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,
),
],
),
You can use package flutter_linkify
https://pub.dev/packages/flutter_linkify
Just want to provide another option.
Package will divide your text and highlight http/https automatically
Combine plugin url_launcher you can launch url
You can check example below:
full code below
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';
}
}
}
You can use Link Text https://pub.dev/packages/link_text and use it like
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,
),
),
);
}
In Flutter 2.0, the Link widget was introduced. Use this widget to launch webpages and also navigate to new screens in your app. you need to use the url_launcher package before using it.
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,
),
),
);
},
),
You could use the flutter_html plugin if you want to have more advanced text capabilities:
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...
},
)
This is just the tip of the iceberg of capabilities with this plugin.
Just a thought : You could even host parts of your flutter app online as html and render them in flutter as widgets with this plugin.
An alternative (or not) way to put clickable links in your app (for me it just worked that way):
1 - Add the url_launcher package in your pubspec.yaml file
(the package version 5.0 didn't work well for me, so I'm using the 4.2.0+3).
dependencies:
flutter:
sdk: flutter
url_launcher: ^4.2.0+3
2 - Import it and use as below.
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';
}
}
}
Here is a turn-key package https://pub.dev/packages/link_text
child: LinkText(
'Hello check http://google.com',
textStyle: ...,
),
Safer to use a library for this kind of complexity
Pros:
The answers to this question that suggest using RichText<\/code> with a
TextSpan<\/code> +
GestureRecognizer<\/code> are all functionally correct, but from the UX perspective, they do not provide feedback to the user responding to the touch.
To maintain consistency with other Material widgets, you could use a similar approach, but use a
WidgetSpan<\/code> +
InkWell<\/code> instead.
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';
}
}
}
Adding one more simple and neat trick because the above ones are over-complicated for some use cases. I did it using RichText - WidgetSpan, TextButton and URL launcher package. Just modify the below example block according to your needs.
Code:
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"),
),
),
],
),
),
),
],
);
}
}
this could be late; but I found this package
https://github.com/Sub6Resources/flutter_html
combined with url launcher https://pub.dev/packages/url_launcher
can give us a great html link inside on widgets like (including html href) on tap
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;
},
)
all credits to the autor.
cheers.
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.