Android Linkify e i collegamenti testuali
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:
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);
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);
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
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=00100In questo caso il suffisso http:// è associata ad una risorsa web mentre se viene utilizzato il suffisso del tipo:
content://<authority>/pathl'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:
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:
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.