Как создать гиперссылку в виджете Flutter?

97

Я хотел бы создать гиперссылку для отображения в моем приложении Flutter.

Гиперссылка должна быть встроена в Textтекстовое представление или подобные ему, например:

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

Есть намек на это?

TaylorR
источник

Ответы:

161

Просто оберните InkWell вокруг текстового виджета и укажите 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('UrlLauchner'),
        ),
        body: new Center(
          child: new InkWell(
              child: new Text('Open Browser'),
              onTap: () => launch('https://docs.flutter.io/flutter/services/UrlLauncher-class.html')
          ),
        ),
      ),
    );
  }
}

Вы можете задать стиль виджету «Текст», чтобы он выглядел как ссылка.

Обновить

Немного изучив проблему, я нашел другое решение для реализации запрашиваемых вами гиперссылок. Вы можете использовать виджет 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');
                  },
                ),
              ],
            ),
          ),
        ),
      ),
    );
  }
}

Таким образом вы можете выделить одно слово и сделать из него гиперссылку;)

Райнер Виттманн
источник
7
UrlLauncher больше не является частью флаттера, он был перемещен в плагин, а API изменен .
Йозеф Адамчик
7
Также нам нужно добавить импорт: import 'package: flutter / gestures.dart'; import 'package: url_launcher / url_launcher.dart';
Alex Pliutau
4
Вы TapGestureRecognizerнеправильно управляете жизненным циклом своего . Вы должны вызвать dispose()метод, когда RichTextон больше не используется. Смотрите здесь: api.flutter.dev/flutter/painting/TextSpan/recognizer.html
Алекс Семенюк
@AlexSemeniuk В вашем примере они используют StatefulWidget, в ответе выше это StatelessWidget. Вы уверены, что нам нужно избавиться от корпуса StatelessWidget?
Кори Коул
2
@CoreyCole StatelessWidgetне избавится TapGestureRecognizerот вас волшебным образом . Фактически, использование StatelessWidgetв этом сценарии неверно, так как вы не можете таким образом распорядиться своими источниками. И да, вам абсолютно необходимо вызвать dispose()метод TapGestureRecognizer, поскольку он запускает внутренний таймер, который необходимо остановить.
Алекс Семенюк
44

Flutter не имеет встроенной поддержки гиперссылок, но вы можете подделать ее самостоятельно. Пример есть в drawer.dart галереи . Они используют RichTextвиджет, содержащий цветной объект TextSpan, у которого есть 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,
              ),
            ],
          ),

гиперссылка браузер

Коллин Джексон
источник
Спасибо. Но на самом деле я ищу не это: я ищу не только навигацию внутри приложения.
TaylorR
Я не совсем понимаю, что вы подразумеваете под «выходом за рамки навигации в приложении». Вы хотите, чтобы ссылка открывала браузер?
Коллин Джексон
Да, ссылку или что-то подобное, по которой можно щелкнуть, чтобы открыть в обзоре.
TaylorR
1
Это то, что делает образец, на который я ссылался. Я добавил несколько картинок к ответу, чтобы показать его.
Коллин Джексон
Ссылка репо нарушена
Мишель Файнштейн
39

Вы можете обернуть 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
  }
)

введите описание изображения здесь

CopsOnRoad
источник
Вы правы, в вашем решении меньше строк, чем в других, но Inkwell - это виджет для этой конкретной работы, так что, по крайней мере, семантически я думаю, что это лучшее решение
dmarquina
2
@dmarquina Да, вы можете использовать InkWellвместо GestureDetector.
CopsOnRoad
7

Если вы хотите сделать его еще более похожим на ссылку, вы можете добавить подчеркивание:

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

и результат:

введите описание изображения здесь

бартектартанус
источник
Это не кликабельно!
atilkan
Затем оберните его виджетом Button. :)
bartektartanus
7

Вы можете использовать пакет 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';
    }
  }
}
Chunhunghan
источник
Как у вас может быть 2 ссылки на одном виджете? Например, «щелкая здесь, вы принимаете условия использования и политику конфиденциальности», где нам нужно, чтобы они были вместе
Дани
1

Альтернативный (или нет) способ разместить интерактивные ссылки в вашем приложении (для меня это просто сработало):

1 - Добавьте пакет url_launcher в свой файл pubspec.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';
    }
  }
}
Феллипе Санчес
источник
Если нужна гиперссылка между некоторым текстом, вы можете использовать FlatButtonс тем же фоном и цветом текста, что и остальные ваши тексты, поэтому отформатируйте его с помощью TextDecoration.underline, как показано выше на bartektartanus ...
Феллипе Санчес
0

Вы можете использовать текст ссылки 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 pub getдля этого не получаетсяUnable to find a plugin.vcxproj for plugin "url_launcher_windows"
Евгений Гр. Филиппов