android - por - Abra los enlaces de TextView en otra actividad, no en el navegador predeterminado
como quitar navegador predeterminado (5)
Al tener el textView con autoLinkMask
configurado en Linkify.ALL
, puedo abrir los enlaces y el navegador muestra la página web.
Necesito llamar a otra actividad que lo hará con su webView que no abandona la aplicación.
Notas importantes:
- cambiar el contenido de textView no es una opción, necesito que se muestren los enlaces tal como están con los esquemas que tienen,
- Hay mucho texto en el textView, no solo el enlace.
Miré a través de movementMethod
y IntentFilters
, podría fallar algo pero parece que no puede ayudar.
Entonces, ¿alguna opción para interceptar el enlace que se toca en TextView
para hacer algo con él sin abrir el navegador?
Si desea mencionar this pregunta SO, por favor proporcione algunos argumentos por los que la causa no parece resolver el mismo problema que yo.
Creo que la respuesta de David Hedlund a sí mismo es el camino a seguir. En mi caso, tenía un TextView que contenía la bandeja de entrada del usuario del contenido de SMS y quería controlar el siguiente comportamiento:
- Si se encuentra una URL de la WEB, vincútela y administre el clic dentro de la aplicación.
- Si se encuentra el NÚMERO DE TELÉFONO, vincúlelo y administre el clic que muestra un selector para permitir al usuario elegir si llama al número o lo agrega a la libreta de direcciones (todo dentro de la aplicación)
Para lograr esto utilicé la respuesta enlazada de esta manera:
TextView tvBody = (TextView)findViewById(R.id.tvBody);
tvBody.setText(messageContentString);
// now linkify it with patterns and scheme
Linkify.addLinks(tvBody, Patterns.WEB_URL, "com.my.package.web:");
Linkify.addLinks(tvBody, Patterns.PHONE, "com.my.package.tel:");
Ahora en el manifiesto:
<activity
android:name=".WebViewActivity"
android:label="@string/web_view_activity_label">
<intent-filter>
<category android:name="android.intent.category.DEFAULT" />
<action android:name="android.intent.action.VIEW"/>
<data android:scheme="com.duckma.phonotto.web"/>
</intent-filter>
</activity>
...
<activity
android:name=".DialerActivity"
android:label="@string/dialer_activity_label">
<intent-filter>
<category android:name="android.intent.category.DEFAULT" />
<action android:name="android.intent.action.VIEW"/>
<data android:scheme="com.duckma.phonotto.tel"/>
</intent-filter>
</activity>
<activity
android:name=".AddressBook"
android:label="@string/address_book_activity_label">
<intent-filter>
<category android:name="android.intent.category.DEFAULT" />
<action android:name="android.intent.action.VIEW"/>
<data android:scheme="com.duckma.phonotto.tel"/>
</intent-filter>
</activity>
Y funciona bien para mí, cuando el usuario hace clic en un número de teléfono, el selector se mostrará con el marcador / libreta de direcciones. En las actividades llamadas use getIntent().getData()
para encontrar la URL pasada con los datos en ella.
Hago que el código de @ CommonsWare sea más elegante y claro al agregar Click Listener, que se puede agregar directamente al mismo método que reemplaza los intervalos de URL.
Defina la
YourCustomClickableSpan Class
.public static class YourCustomClickableSpan extends ClickableSpan { private String url; private OnClickListener mListener; public YourCustomClickableSpan(String url, OnClickListener mListener) { this.url = url; this.mListener = mListener; } @Override public void onClick(View widget) { if (mListener != null) mListener.onClick(url); } public interface OnClickListener { void onClick(String url); } }
Defina la
RichTextUtils Class
que manipulará el texto distribuido de su TextView.public static class RichTextUtils { public static <A extends CharacterStyle, B extends CharacterStyle> Spannable replaceAll ( Spanned original, Class<A> sourceType, SpanConverter<A, B> converter, final ClickSpan.OnClickListener listener) { SpannableString result = new SpannableString(original); A[] spans = result.getSpans(0, result.length(), sourceType); for (A span : spans) { int start = result.getSpanStart(span); int end = result.getSpanEnd(span); int flags = result.getSpanFlags(span); result.removeSpan(span); result.setSpan(converter.convert(span, listener), start, end, flags); } return (result); } public interface SpanConverter<A extends CharacterStyle, B extends CharacterStyle> { B convert(A span, ClickSpan.OnClickListener listener); } }
Defina la
URLSpanConverter class
que realizará el código real de reemplazo URLSpan con su intervalo personalizado.public static class URLSpanConverter implements RichTextUtils.SpanConverter<URLSpan, ClickSpan> { @Override public ClickSpan convert(URLSpan span, ClickSpan.OnClickListener listener) { return (new ClickSpan(span.getURL(), listener)); } }
Uso
TextView textView = ((TextView) this.findViewById(R.id.your_id)); textView.setText("your_text"); Linkify.addLinks(contentView, Linkify.ALL); Spannable formattedContent = UIUtils.RichTextUtils.replaceAll((Spanned)textView.getText(), URLSpan.class, new UIUtils.URLSpanConverter(), new UIUtils.ClickSpan.OnClickListener() { @Override public void onClick(String url) { // Call here your Activity } }); textView.setText(formattedContent);
Tenga en cuenta que aquí definí todas las clases como estáticas para que pueda poner directamente información sobre su clase Util y luego hacer referencia a ella fácilmente desde cualquier lugar.
Paso # 1: crea tu propia subclase de ClickableSpan
que hace lo que quieres con su método onClick()
(por ejemplo, llamado YourCustomClickableSpan
)
Paso # 2: Ejecuta una conversión masiva de todos los objetos URLSpan
para que YourCustomClickableSpan
objetos YourCustomClickableSpan
. Tengo una clase de utilidad para esto:
public class RichTextUtils {
public static <A extends CharacterStyle, B extends CharacterStyle> Spannable replaceAll(Spanned original,
Class<A> sourceType,
SpanConverter<A, B> converter) {
SpannableString result=new SpannableString(original);
A[] spans=result.getSpans(0, result.length(), sourceType);
for (A span : spans) {
int start=result.getSpanStart(span);
int end=result.getSpanEnd(span);
int flags=result.getSpanFlags(span);
result.removeSpan(span);
result.setSpan(converter.convert(span), start, end, flags);
}
return(result);
}
public interface SpanConverter<A extends CharacterStyle, B extends CharacterStyle> {
B convert(A span);
}
}
Lo usarías así:
yourTextView.setText(RichTextUtils.replaceAll((Spanned)yourTextView.getText(),
URLSpan.class,
new URLSpanConverter()));
con un URLSpanConverter
personalizado como este:
class URLSpanConverter
implements
RichTextUtils.SpanConverter<URLSpan, YourCustomClickableSpan> {
@Override
public URLSpan convert(URLSpan span) {
return(new YourCustomClickableSpan(span.getURL()));
}
}
para convertir todos los objetos YourCustomClickableSpan
objetos YourCustomClickableSpan
.
Que hacer esto
TextView textView=(TextView) findViewById(R.id.link);
textView.setOnClickListener(new OnClickListener() {
public void onClick(View v) {
Intent intent=new Intent(YourActivityName.this,WebActivity.class);
startActivity(intent);
}
});
onCreate de WebActivity Class:
WebView webView=(WebView) findViewById(R.id.web);
webView.loadUrl("http://www.google.co.in");
Agregue esto bajo textview en xml:
android:clickable="true"
Solo para compartir una solución alternativa usando Textoo que acabo de crear:
TextView yourTextView = Textoo
.config((TextView) findViewById(R.id.your_text_view))
.addLinksHandler(new LinksHandler() {
@Override
public boolean onClick(View view, String url) {
if (showInMyWebView(url)) {
//
// Your custom handling here
//
return true; // event handled
} else {
return false; // continue default processing i.e. launch browser app to display link
}
}
})
.apply();
Bajo el capó, la biblioteca reemplaza URLSpan
en TextView con una implementación personalizada de ClickableSpan
que distribuye eventos de clic a los LinksHandler
proporcionados por el usuario. El mecanismo es muy similar a la solución de @commonsWare. Simplemente empaquete en una API de nivel superior para que sea más fácil de usar.