Android Linkify e i collegamenti testuali

di  Antonio Coschignano, giovedì 30 dicembre 2010
La piattaforma Android fornisce un modo semplice per convertire automaticamente modelli di testo in link cliccabili. Per impostazione predefinita, Android sa riconoscere web url, indirizzi email, indirizzi di mappa e numeri di telefono. Questa funzionalità viene implementata nella classe Linkify che non solo ci permette di trasformare il testo in un link ma anche di lanciare un azione appropriata a secondo della tipologia di testo con cui abbiamo a che fare. Ad esempio se il testo è un web url allora un click su di esso genera l'apertura del browser, mentre se abbiamo a che fare con un numero di telefono si aprirà la rubrica telefonica etc.. Questa proprietà può essere applicata sia ad una TextView o direttamente ad un'oggetto di tipo Spannable. Attraverso alcuni esempi vi mostrerò come applicare i modelli di testo già integrati nella piattaforma e come costruire quelli personalizzabili.

Default Linkify

Vediamo un esempio per effettuare una trasformazione su di un testo all'interno di una TextView:

import android.text.util.Linkify;
.....
TextView textViewWebUrl = ...
String text = "Esempio Linkify Web Url www.simplesoft.it";
textViewWebUrl.setText(textWebUrls);
Linkify.addLinks(textViewWebUrl, Linkify.WEB_URLS);
Il metodo statico addLinks() applica la trasformazione alla TextView (Linkify.WEB_URLS), quindi vengono identificati e trasformati solo le Web Urls:

Esempio Android Linkify 1

Un click sul link lancia implicitamente una Intent che avvia il caricamento del browser di Android per visualizzare la pagina richiesta. Stessa cosa succede se invece applichiamo il Linkify per i numeri di telefono con la differenza che la Intent invece di lanciare il browser invoca il caricamento della rubrica con il numero selezionato:

import android.text.util.Linkify;
.....
TextView textView = ...
String text = "Esempio Linkify Phone Number +39099999999";
textView.setText(text);
Linkify.addLinks(textView, Linkify.PHONE_NUMBERS);

Esempio Android Linkify 2

Un altro tipo di collegamento che merita particolare attenzione è il Linkify.MAP_ADDRESSES che applicato ad un indirizzo che segue una certa sintassi del tipo '1600 Amphitheatre Parkway, Mountain View, CA', un click su di esso visualizza l'indirizzo nell'applicazione Google Maps. Facciamo un breve esempio:

TextView textViewMap = ....
String textMap = "Indirizzo 1600 Amphitheatre Parkway, Mountain View, CA";
textViewMap.setText(textMap);
Linkify.addLinks(textViewMap, Linkify.MAP_ADDRESSES);

Esempio Android Linkify 3

Purtroppo in questo caso sembra che il link viene applicato solo per gli indirizzi americani. Se ad esempio compare la stringa IT il link non viene applicato.

Oltre a questi che abbiamo visto abbiamo per ultimo il tipo Linkify.EMAIL_ADDRESSES che viene applicato per gli indirizzi email e si interfaccia con l'applicazione per la posta elettronica. Se vogliamo applicare ad un testo tutti i tipi di trasformazione disponibili di default nella piattaforma basta specificare la costante Linkify.ALL. Invece per applicare solo alcuni tipi di modelli bisogna utilizzare il 'pipe':

Linkify.addLinks(textView, Linkify.WEB_URLS | Linkify.EMAIL_ADDRESSES);
Mentre per disattivare qualsiasi modello di link bisogna usare il valore '0':
Linkify.addLinks(textView, 0);
Il widget TextView comuqnue dispone dell'attributo android:autoLink che controlla i tipi di modelli di testo che vengono automaticamente riconosciuti e convertiti in link cliccabili:
<TextView
  ...
  android:autoLink="web|email|phone"
  ...
/>
Questo attributo è un modo conveniente per attivare uno o più dei modelli di link poichè può essere configurato direttamente da layout XML senza che ciò implichi codice aggiuntivo.

Link Patterns personalizzati

Oltre a questo che abbiamo visto la classe Linkify include anche un meccanismo flessibile di riconoscimento e conversione di modelli di testo personalizzabili:

Linkify.addLink(TextView view, Pattern pattern, String scheme);
Quindi possiamo sfruttare questa possibilità e applicare un nostro modello personalizzato utilizzando le Java Regex. Per creare un modello bisogna prima specificare un'espressione regolare che ci consente di identificare il link ed uno schema di una risorsa dove accodare la stringa identificata. Lo schema non deve essere necessariamente una risorsa web ma un qualsiasi tipo di risorsa gestita da un ContentProvider. Altri tipi di schemi vengono utilizzati implicitamente nei modelli di default che abbiamo visto. Essi sono:
  • 'tel:' Numeri Telefonici
  • 'mailto:' Email
  • 'http//:', 'https://', 'rtsp://:' risorse web
  • 'geo:' per le mappe

Quindi tramite lo schema specificato viene lanciata l'Intent corrispondente.

Vediamo un esempio che ci consente di cercare le zone geografiche associate ad un CAP (Codice Avviamento Postale) sfruttanto il servizio web offerto dal sito www.moduli.it:

TextView textViewCap = ...
String text = "Codice CAP 00100"
Pattern pattern = Pattern.compile("([0-9]{5})");
String schema = "http://www.moduli.it/caprev.php?cap=";
Linkify.addLinks(textViewCap, pattern, schema);
Abbiamo definito un'espressione regolare che identifica un CAP. Quindi una volta identificato viene trasformato in link ed un click su di esso genera una chiamata http alla risorsa definita nello schema con il CAP identificato. Di conseguenza viene aperto il browser che visualizza i risultati della seguente query http:
http://www.moduli.it/caprev.php?cap=00100
In questo caso il suffisso http:// è associata ad una risorsa web mentre se viene utilizzato il suffisso del tipo:
content://<authority>/path
l'azione viene trasmessa al ContentProvider corrispondente.

Match e Trasform Filters

Esaminiamo adesso un'altro aspetto che la classe Linkify ci mette a disposizione. Infatti contiene un'altra tipologia di metodo dove è possibile personalizzare alcune trasformazioni sui modelli di testo definiti:

Linkify.addLink(TextView view, Pattern pattern, String scheme,
                Linkify.MatchFilter matchFilter,
                Linkify.TransformFilter transformFilter);
Come vedete abbiamo abbiamo due tipi di oggetti che sono le interfacce Linkify.MatchFilter e Linkify.TransformFilter che ci consentono di avere un maggiore controllo sui modelli di testo che intendiamo implementare.

Il MathFilter

Il MatchFilter ci consente di filtrare i testi che sono stati identificato come link. Ad esempio se applichiamo un modello di testo per l'email e vogliamo che la trasformazione venga applicata solo al dominio '@gmail.com' ignorando le altre allora bisogna definire un MatchFilter per questo scopo. Vediamo un esempio:

TextView textView = new TextView(this);
String text = "Il mio indirizzio gmail : email@gmail.com, " +
              "il mio indirizzo hotmail: email@hotmail.com";

//Questo è il pattern di riconoscimento email
Pattern EMAIL_ADDRESS = Pattern.compile(
  "[a-zA-Z0-9\\+\\.\\_\\%\\-\\+]{1,256}" +
  "\\@" +
  "[a-zA-Z0-9][a-zA-Z0-9\\-]{0,64}" +
    "(" +
      "\\." +
      "[a-zA-Z0-9][a-zA-Z0-9\\-]{0,25}" +
    ")+"
);
textView.setText(text);
Linkify.addLinks(textView, EMAIL_ADDRESS, "mailto:", new DemoMathFilter(),null);
Il DemoMatchFilter è cosi definito:
class DemoMathFilter implements MatchFilter {

  @Override
  public boolean acceptMatch(CharSequence s, int start, int end) {
    String str = s.subSequence(start, end).toString();
    if(str.toLowerCase().contains("gmail")) return true;
    else return false;
  }
}
Quindi ogni stringa identificata viene filtrata da questo metodo che controlla se contiene la sottostringa 'gmail' con il risultato seguente:

Esempio Android Linkify 4

Il TransformFilter

Il TransformFilter invece ci consente di avere un controllo sulla rappresentazione del link identificato. Questo trasformazione viene applicata al testo implicito nel link. Ad esempio sempre per l'email, possiamo trasformare il testo tutto in minuscolo:

TextView textView = new TextView(this);
String text = "Il mio indirizzio gmail : MIAEMAIL@GMAIL.COM "

//Questo è il pattern di riconoscimento email
Pattern EMAIL_ADDRESS = Pattern.compile(
  "[a-zA-Z0-9\\+\\.\\_\\%\\-\\+]{1,256}" +
  "\\@" +
  "[a-zA-Z0-9][a-zA-Z0-9\\-]{0,64}" +
    "(" +
      "\\." +
      "[a-zA-Z0-9][a-zA-Z0-9\\-]{0,25}" +
    ")+"
);
textView.setText(text);
Linkify.addLinks(textView, EMAIL_ADDRESS, "mailto:", null, new DemoTransformFilter());

.....

private class DemoTransformFilter implements TransformFilter {

 @Override
 public String transformUrl(Matcher match, String url) {
 	return url.toLowerCase();
 }

}
La trasformazione non viene applicata al testo visualizzato ma bensì al testo trasferito allo schema scelto:

Esempio Android Linkify 4

Conclusioni e approfondimenti

E' evidente che per l'implementazione di un modello personalizzato bisogna avere una buona dimestichezza con le espressioni regolari. Se poi abbiamo anche bisogno di utilizzare altri tipi di componenti a cui associare i modelli di testo bisogna approfondire la conoscenza del funzionamento dei ContentProviders, le Intent associate alle Activity e tutto quello strato di logica che consente ai diversi componenti di interagire fra di loro.

Altri link che potrebbero interessarti
  • » Struttura di un'applicazione Android
  • » Screenshot su un dispositivo Android
  • » Pubblicare applicazioni nell'Android Market
  • » Integrare Google Analytics nelle applicazioni Android
  • » Integrare AdMob nelle applicazioni Android
  • » Guida all'installazione dell'Android SDK
  • » Guida agli Adapter e le ListView in Android
  • » Gestire Thread e GUI nelle applicazioni Android
  • » Applicazioni Android ed il supporto multilingue
  • » Android VideoView e le Youtube Api
  • » Android HTML TextView
  • » Android e tecniche multithreading
  • » Android e la gestione dei sensori
  • » Android e l'interfaccia Parcelable