简体   繁体   English

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

[英]How to create a hyperlink in Flutter widget?

I would like to create a hyperlink to display in my Flutter app.我想创建一个超链接以显示在我的 Flutter 应用程序中。

The hyper link should be embedded in a Text or similar text views like:超链接应嵌入Text或类似的文本视图中,例如:

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.只需在 Text 小部件周围包裹一个 InkWell,并为 onTap 属性提供一个 UrlLauncher(来自服务库)。 InstallUrlLauncher as a Flutter package before using it below.在下面使用之前,将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')
          ),
        ),
      ),
    );
  }
}

You can supply a style to the Text widget to make it look like a link.您可以为 Text 小部件提供样式,使其看起来像一个链接。

Update更新

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 .您可以将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');
                  },
                ),
              ],
            ),
          ),
        ),
      ),
    );
  }
}

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. Flutter 没有内置的超链接支持,但你可以自己伪造它。 There's an example in the Gallery's drawer.dart . Gallery 的 drawer.dart 中有一个例子。 They use a RichText widget containing a coloured TextSpan , which has a recognizer attribute to handle taps:他们使用包含彩色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,
              ),
            ],
          ),

超链接 浏览器

You can wrap your Text in GestureDetector and handle click in onTap() .您可以将您的Text包装在GestureDetector并处理onTap()点击。

GestureDetector(
  child: Text("Click here", style: TextStyle(decoration: TextDecoration.underline, color: Colors.blue)),
  onTap: () {
    // do what you need to do when "Click here" gets clicked
  }
)

在此处输入图片说明

You can use package flutter_linkify您可以使用包 flutter_linkify
https://pub.dev/packages/flutter_linkify https://pub.dev/packages/flutter_linkify
Just want to provide another option.只是想提供另一种选择。
Package will divide your text and highlight http/https automatically包将分割您的文本并自动突出显示 http/https
Combine plugin url_launcher you can launch url结合插件 url_launcher 你可以启动 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';
    }
  }
}

If you want to make it look even more like a link, you can add underline:如果你想让它看起来更像一个链接,你可以添加下划线:

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

and the result:结果:

在此处输入图片说明

You can use Link Text https://pub.dev/packages/link_text and use it like您可以使用链接文本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,
      ),
    ),
  );
}

颤动链接小部件

In Flutter 2.0, the Link widget was introduced.在 Flutter 2.0 中,引入了 Link 小部件。 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 包。

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,
                ),
              ),
            );
          },
        ),

You could use the flutter_html plugin if you want to have more advanced text capabilities:如果您想拥有更高级的文本功能,可以使用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...
  },
)

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.只是一个想法:您甚至可以将 flutter 应用程序的部分在线托管为 html 并使用此插件将它们作为小部件呈现在 flutter 中。

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 1 - 在 pubspec.yaml 文件中添加 url_launcher 包

(the package version 5.0 didn't work well for me, so I'm using the 4.2.0+3). (包版本 5.0 对我来说效果不佳,所以我使用的是 4.2.0+3)。

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

2 - Import it and use as below. 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';
    }
  }
}

Here is a turn-key package https://pub.dev/packages/link_text这是一个交钥匙 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:优点:

  • takes in the entire string as a single param将整个字符串作为单个参数
  • parses the links and renders them into the UI as clickable, inline with the non-clickable text解析链接并将它们呈现到 UI 中作为可点击的,与不可点击的文本内联
  • no complex RichText structure required不需要复杂的 RichText 结构

You can use packages like Link,Link_Text,linkify etc.. for this purpose. 为此,您可以使用Link,Link_Text,linkify等软件包。

Just search link in pub.dev packages and you will get good packages to add links easily. 只需在pub.dev软件包中搜索链接 ,您将获得优质的软件包,可以轻松添加链接。

这是来自link_text包的图片

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.建议将RichText<\/code>与TextSpan<\/code> + GestureRecognizer<\/code>一起使用的问题的答案在功能上都是正确的,但从 UX 的角度来看,它们不会向响应触摸的用户提供反馈。 To maintain consistency with other Material widgets, you could use a similar approach, but use a WidgetSpan<\/code> + InkWell<\/code> instead.为了保持与其他 Material 小部件的一致性,您可以使用类似的方法,但改用WidgetSpan<\/code> + InkWell<\/code> 。

This example uses the url_launcher<\/a> package and an unstyled InkWell, but you can customize as you see fit:此示例使用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';
    }
  }
}

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.我使用 RichText - WidgetSpan、TextButton 和 URL 启动器 package 完成了它。 Just modify the below example block according to your needs.只需根据您的需要修改以下示例块。

Result:结果: 结果

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 https://github.com/Sub6Resources/flutter_html

combined with url launcher https://pub.dev/packages/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链接,例如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;
  },
)

all credits to the autor. 所有学分都归授给导师。

cheers. 干杯。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM