Como criar um hiperlink no widget Flutter?

103

Gostaria de criar um hiperlink para exibir no meu aplicativo Flutter.

O hiperlink deve ser incorporado em uma Textou em visualizações de texto semelhantes, como:

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

Alguma dica para fazer isso?

TaylorR
fonte

Respostas:

169

Basta envolver um InkWell em um widget de texto e fornecer um UrlLauncher (da biblioteca de serviço) para o atributo onTap. Instale UrlLauncher como um pacote Flutter antes de usá-lo abaixo.

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

Você pode fornecer um estilo ao widget de Texto para torná-lo semelhante a um link.

Atualizar

Depois de examinar o problema um pouco, encontrei uma solução diferente para implementar os hiperlinks 'em linha' que você pediu. Você pode usar o widget RichText com TextSpans incluídos .

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

Desta forma, você pode realmente destacar uma palavra e fazer um hiperlink a partir dela;)

Rainer Wittmann
fonte
7
UrlLauncher não faz mais parte do flutter, ele foi movido para um plug-in e a API foi alterada .
Josef Adamcik
7
Também precisamos adicionar importações: import 'package: flutter / gestures.dart'; import 'package: url_launcher / url_launcher.dart';
Alex Pliutau
5
Você não está lidando com o seu ciclo de vida TapGestureRecognizercorretamente. Você deve chamar o dispose()método quando RichTextnão for mais usado. Veja aqui: api.flutter.dev/flutter/painting/TextSpan/recognizer.html
Alex Semeniuk
@AlexSemeniuk Em seu exemplo, eles estão usando um StatefulWidget, na resposta acima é um StatelessWidget. Tem certeza de que precisamos descartar o caso de um StatelessWidget?
Corey Cole,
2
@CoreyCole StatelessWidgetnão descartará magicamente o seu TapGestureRecognizerpara você. Na verdade, usar StatelessWidgetneste cenário é incorreto, pois você não pode descartar seus recursos dessa forma. E sim, você absolutamente precisa chamar o dispose()método de TapGestureRecognizer, pois ele executa o cronômetro interno que precisa ser interrompido.
Alex Semeniuk
50

Flutter não tem suporte para hiperlinks embutido, mas você mesmo pode fingir. Há um exemplo em drawer.dart da Galeria . Eles usam um RichTextwidget que contém um colorido TextSpan, que tem um recognizeratributo para lidar com os toques:

        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,
              ),
            ],
          ),

hiperlink navegador

Collin Jackson
fonte
Obrigado. Mas isso não é realmente o que estou procurando: estou olhando além da navegação no aplicativo.
TaylorR
Não tenho certeza do que você quer dizer com "olhar além da navegação no aplicativo". Você quer que o link abra um navegador?
Collin Jackson,
Sim, um link ou semelhante que pode ser clicado para abrir em um navegador.
TaylorR
1
Isso é o que faz o exemplo vinculado a mim. Adicionei algumas fotos à resposta para mostrar isso.
Collin Jackson,
O link do repo está quebrado
Michel Feinstein
41

Você pode quebrar o seu Textem GestureDetectore alça clique em 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
  }
)

insira a descrição da imagem aqui

CopsOnRoad
fonte
Você está certo, sua solução tem menos linhas do que as outras, mas Inkwell é o widget para esse trabalho específico, então pelo menos semanticamente acho que é a melhor solução
dmarquina
2
@dmarquina Sim, você pode usar no InkWelllugar de GestureDetector.
CopsOnRoad
9

Se quiser que pareça ainda mais com um link, você pode adicionar sublinhado:

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

e o resultado:

insira a descrição da imagem aqui

Bartektartanus
fonte
Não é clicável!
atilkan,
Em seguida, envolva-o com o widget Botão. :)
bartektartanus
8

Você pode usar o pacote flutter_linkify
https://pub.dev/packages/flutter_linkify
Apenas deseja fornecer outra opção.
O pacote irá dividir seu texto e destacar http / https automaticamente.
Combine o plugin url_launcher você pode lançar o url
Você pode verificar o exemplo abaixo:

insira a descrição da imagem aqui

código completo abaixo

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: [email protected] \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
fonte
Como você pode ter 2 links no mesmo widget? Por exemplo, "clicando aqui, você aceita os termos de uso e a política de privacidade", onde precisamos tê-los juntos
Dani
1

Uma forma alternativa (ou não) de colocar links clicáveis ​​em seu aplicativo (para mim, funcionou dessa forma):

1 - Adicione o pacote url_launcher em seu arquivo pubspec.yaml

(o pacote versão 5.0 não funcionou bem para mim, então estou usando o 4.2.0 + 3).

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

2 - Importe e use conforme abaixo.

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';
    }
  }
}
Fellipe Sanches
fonte
Se precisar de um hiperlink entre algum texto, você pode usar um FlatButtoncom as mesmas cores de fundo e de texto do restante de seus textos, então formate-o com TextDecoration.underline como o bartektartanus mostrado acima ...
Fellipe Sanches
1

Você pode usar Link Text https://pub.dev/packages/link_text e usá-lo como

 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,
      ),
    ),
  );
}
Syed Ahsan Ali
fonte
No Linux flutter pub getporque ele falha comUnable to find a plugin.vcxproj for plugin "url_launcher_windows"
Eugene Gr. Philippov