manejar el enlace de vista de texto, haga clic en mi aplicación de Android
Actualmente estoy renderizando la entrada HTML en un TextView de esta manera:
tv.setText(Html.fromHtml("<a href='test'>test</a>"));
El HTML que se muestra me lo proporciona a través de un recurso externo, por lo que no puedo cambiar las cosas como lo haría, pero puedo, por supuesto, alterar algunas expresiones regulares del HTML para cambiar el valor href, por ejemplo, a otra cosa.
Lo que quiero es poder manejar un clic en un enlace directamente desde la aplicación, en lugar de que el enlace abra una ventana del navegador. ¿Es esto algo alcanzable? Supongo que sería posible configurar el protocolo del valor href en algo como "myApp://" y luego registrar algo que permita a mi aplicación manejar ese protocolo. Si esta es realmente la mejor manera, me gustaría saber cómo se hace, pero espero que haya una manera más fácil de simplemente decir "cuando se hace clic en un enlace en esta vista de texto, quiero generar un evento que reciba el valor href del enlace como parámetro de entrada"
Llegando a esto casi un año después, hay una manera diferente en la que resolví mi problema particular. Como quería que el enlace fuera manejado por mi propia aplicación, existe una solución que es un poco más simple.
Además del filtro de intención predeterminado, simplemente dejo que mi actividad objetivo escuche las ACTION_VIEW
intenciones y, específicamente, aquellas con el esquemacom.package.name
<intent-filter>
<category android:name="android.intent.category.DEFAULT" />
<action android:name="android.intent.action.VIEW" />
<data android:scheme="com.package.name" />
</intent-filter>
Esto significa que los enlaces que comienzan con com.package.name://
serán manejados por mi actividad.
Entonces todo lo que tengo que hacer es construir una URL que contenga la información que quiero transmitir:
com.package.name://action-to-perform/id-that-might-be-needed/
En mi actividad objetivo, puedo recuperar esta dirección:
Uri data = getIntent().getData();
En mi ejemplo, podría simplemente verificar data
si hay valores nulos, porque cuando no sean nulos, sabré que fueron invocados mediante dicho enlace. A partir de ahí, extraigo las instrucciones que necesito de la URL para poder mostrar los datos adecuados.
De otra forma, toma prestado un poco de Linkify pero te permite personalizar su manejo.
Clase de tramo personalizada:
public class ClickSpan extends ClickableSpan {
private OnClickListener mListener;
public ClickSpan(OnClickListener listener) {
mListener = listener;
}
@Override
public void onClick(View widget) {
if (mListener != null) mListener.onClick();
}
public interface OnClickListener {
void onClick();
}
}
Función auxiliar:
public static void clickify(TextView view, final String clickableText,
final ClickSpan.OnClickListener listener) {
CharSequence text = view.getText();
String string = text.toString();
ClickSpan span = new ClickSpan(listener);
int start = string.indexOf(clickableText);
int end = start + clickableText.length();
if (start == -1) return;
if (text instanceof Spannable) {
((Spannable)text).setSpan(span, start, end, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
} else {
SpannableString s = SpannableString.valueOf(text);
s.setSpan(span, start, end, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
view.setText(s);
}
MovementMethod m = view.getMovementMethod();
if ((m == null) || !(m instanceof LinkMovementMethod)) {
view.setMovementMethod(LinkMovementMethod.getInstance());
}
}
Uso:
clickify(textView, clickText,new ClickSpan.OnClickListener()
{
@Override
public void onClick() {
// do something
}
});
si hay varios enlaces en la vista de texto. Por ejemplo, la vista de texto tiene "https://" y "tel no". Podemos personalizar el método LinkMovement y manejar clics para palabras según un patrón. Adjunto se encuentra el método de movimiento de enlaces personalizado.
public class CustomLinkMovementMethod extends LinkMovementMethod
{
private static Context movementContext;
private static CustomLinkMovementMethod linkMovementMethod = new CustomLinkMovementMethod();
public boolean onTouchEvent(android.widget.TextView widget, android.text.Spannable buffer, android.view.MotionEvent event)
{
int action = event.getAction();
if (action == MotionEvent.ACTION_UP)
{
int x = (int) event.getX();
int y = (int) event.getY();
x -= widget.getTotalPaddingLeft();
y -= widget.getTotalPaddingTop();
x += widget.getScrollX();
y += widget.getScrollY();
Layout layout = widget.getLayout();
int line = layout.getLineForVertical(y);
int off = layout.getOffsetForHorizontal(line, x);
URLSpan[] link = buffer.getSpans(off, off, URLSpan.class);
if (link.length != 0)
{
String url = link[0].getURL();
if (url.startsWith("https"))
{
Log.d("Link", url);
Toast.makeText(movementContext, "Link was clicked", Toast.LENGTH_LONG).show();
} else if (url.startsWith("tel"))
{
Log.d("Link", url);
Toast.makeText(movementContext, "Tel was clicked", Toast.LENGTH_LONG).show();
} else if (url.startsWith("mailto"))
{
Log.d("Link", url);
Toast.makeText(movementContext, "Mail link was clicked", Toast.LENGTH_LONG).show();
}
return true;
}
}
return super.onTouchEvent(widget, buffer, event);
}
public static android.text.method.MovementMethod getInstance(Context c)
{
movementContext = c;
return linkMovementMethod;
}
Esto debe llamarse desde la vista de texto de la siguiente manera:
textViewObject.setMovementMethod(CustomLinkMovementMethod.getInstance(context));