J'ai un TextView qui rend HTML de base, contenant plus de 2 liens. Je dois capturer les clics sur les liens et les ouvrir - dans ma propre WebView interne (pas dans le navigateur par défaut).
La méthode la plus courante pour gérer le rendu des liens semble être la suivante:
String str_links = "<a href='http://google.com'>Google</a><br /><a href='http://facebook.com'>Facebook</a>";
text_view.setLinksClickable(true);
text_view.setMovementMethod(LinkMovementMethod.getInstance());
text_view.setText( Html.fromHtml( str_links ) );
Toutefois, cela entraîne l’ouverture des liens dans le navigateur Web interne par défaut (affichant la boîte de dialogue "Action complète à l'aide de ...").
J'ai essayé d'implémenter un onClickListener, qui se déclenche correctement lorsque l'utilisateur clique sur le lien, mais je ne sais pas comment déterminer quel lien a été cliqué ...
text_view.setOnClickListener(new OnClickListener(){
public void onClick(View v) {
// what now...?
}
});
Sinon, j'ai essayé de créer une classe LinkMovementMethod personnalisée et d'implémenter onTouchEvent ...
public boolean onTouchEvent(TextView widget, Spannable text, MotionEvent event) {
String url = text.toString();
// this doesn't work because the text is not necessarily a URL, or even a single link...
// eg, I don't know how to extract the clicked link from the greater paragraph of text
return false;
}
Des idées?
Je suis venu avec une solution qui analyse les liens d'une chaîne HTML et les rend cliquables, puis vous permet de répondre à l'URL.
Basé sur une autre réponse , voici une fonction setTextViewHTML () qui analyse les liens d’une chaîne HTML et les rend cliquables, puis vous permet de répondre à l’URL.
protected void makeLinkClickable(SpannableStringBuilder strBuilder, final URLSpan span)
{
int start = strBuilder.getSpanStart(span);
int end = strBuilder.getSpanEnd(span);
int flags = strBuilder.getSpanFlags(span);
ClickableSpan clickable = new ClickableSpan() {
public void onClick(View view) {
// Do something with span.getURL() to handle the link click...
}
};
strBuilder.setSpan(clickable, start, end, flags);
strBuilder.removeSpan(span);
}
protected void setTextViewHTML(TextView text, String html)
{
CharSequence sequence = Html.fromHtml(html);
SpannableStringBuilder strBuilder = new SpannableStringBuilder(sequence);
URLSpan[] urls = strBuilder.getSpans(0, sequence.length(), URLSpan.class);
for(URLSpan span : urls) {
makeLinkClickable(strBuilder, span);
}
text.setText(strBuilder);
text.setMovementMethod(LinkMovementMethod.getInstance());
}
Cela peut être résolu simplement en utilisant Spannable String. Ce que vous voulez vraiment faire (exigence professionnelle) n’est pas très clair pour moi, donc le code suivant ne donnera pas une réponse exacte à votre situation, mais je suis bien sûr certain que cela vous donnera une idée et vous pourrez résoudre votre problème sur la base du code suivant.
Comme vous le faites, je reçois également des données via une réponse HTTP et j’en ai ajouté quelques soulignés texte dans mon cas "plus" et ce texte souligné ouvrira le navigateur Web lorsque click event.Hope cela vous aidera.
TextView decription = (TextView)convertView.findViewById(R.id.library_rss_expan_chaild_des_textView);
String dec=d.get_description()+"<a href='"+d.get_link()+"'><u>more</u></a>";
CharSequence sequence = Html.fromHtml(dec);
SpannableStringBuilder strBuilder = new SpannableStringBuilder(sequence);
UnderlineSpan[] underlines = strBuilder.getSpans(0, 10, UnderlineSpan.class);
for(UnderlineSpan span : underlines) {
int start = strBuilder.getSpanStart(span);
int end = strBuilder.getSpanEnd(span);
int flags = strBuilder.getSpanFlags(span);
ClickableSpan myActivityLauncher = new ClickableSpan() {
public void onClick(View view) {
Log.e(TAG, "on click");
Intent intent = new Intent(Intent.ACTION_VIEW, Uri.parse(d.get_link()));
mContext.startActivity(intent);
}
};
strBuilder.setSpan(myActivityLauncher, start, end, flags);
}
decription.setText(strBuilder);
decription.setLinksClickable(true);
decription.setMovementMethod(LinkMovementMethod.getInstance());
Vous avez fait comme suit:
text_view.setMovementMethod(LinkMovementMethod.getInstance());
text_view.setText( Html.fromHtml( str_links ) );
avez-vous essayé dans l'ordre inverse, comme indiqué ci-dessous?
text_view.setText( Html.fromHtml( str_links ) );
text_view.setMovementMethod(LinkMovementMethod.getInstance());
et sans:
text_view.setLinksClickable(true);
J'ai le même problème, mais beaucoup de texte est mélangé avec peu de liens et de courriels… Je pense qu'utiliser 'autoLink' est une façon plus simple et plus propre de le faire:
text_view.setText( Html.fromHtml( str_links ) );
text_view.setLinksClickable(true);
text_view.setAutoLinkMask(Linkify.ALL); //to open links
Vous pouvez définir Linkify.EMAIL_ADDRESSES ou Linkify.WEB_URLS s'il n'y en a qu'un seulVous souhaitez utiliser ou définir à partir de la présentation XML
Android:linksClickable="true"
Android:autoLink="web|email"
Les options disponibles sont: None, Web, email, téléphone, carte, tous
Une solution plus propre et meilleure, en utilisant la bibliothèque native de Linkify .
Exemple:
Linkify.addLinks(mTextView, Linkify.ALL);
J'ai implémenté une petite classe à l'aide de laquelle vous pouvez gérer de longs clics sur TextView et des pressions sur les liens dans TextView.
TextView Android:id="@+id/text"
Android:layout_width="wrap_content"
Android:layout_height="wrap_content"
Android:autoLink="all"/>
import Android.content.Context;
import Android.text.Layout;
import Android.text.Spannable;
import Android.text.method.LinkMovementMethod;
import Android.text.style.ClickableSpan;
import Android.util.Patterns;
import Android.view.GestureDetector;
import Android.view.MotionEvent;
import Android.widget.TextView;
public class TextViewClickMovement extends LinkMovementMethod {
private final String TAG = TextViewClickMovement.class.getSimpleName();
private final OnTextViewClickMovementListener mListener;
private final GestureDetector mGestureDetector;
private TextView mWidget;
private Spannable mBuffer;
public enum LinkType {
/** Indicates that phone link was clicked */
PHONE,
/** Identifies that URL was clicked */
WEB_URL,
/** Identifies that Email Address was clicked */
EMAIL_ADDRESS,
/** Indicates that none of above mentioned were clicked */
NONE
}
/**
* Interface used to handle Long clicks on the {@link TextView} and taps
* on the phone, web, mail links inside of {@link TextView}.
*/
public interface OnTextViewClickMovementListener {
/**
* This method will be invoked when user press and hold
* finger on the {@link TextView}
*
* @param linkText Text which contains link on which user presses.
* @param linkType Type of the link can be one of {@link LinkType} enumeration
*/
void onLinkClicked(final String linkText, final LinkType linkType);
/**
*
* @param text Whole text of {@link TextView}
*/
void onLongClick(final String text);
}
public TextViewClickMovement(final OnTextViewClickMovementListener listener, final Context context) {
mListener = listener;
mGestureDetector = new GestureDetector(context, new SimpleOnGestureListener());
}
@Override
public boolean onTouchEvent(final TextView widget, final Spannable buffer, final MotionEvent event) {
mWidget = widget;
mBuffer = buffer;
mGestureDetector.onTouchEvent(event);
return false;
}
/**
* Detects various gestures and events.
* Notify users when a particular motion event has occurred.
*/
class SimpleOnGestureListener extends GestureDetector.SimpleOnGestureListener {
@Override
public boolean onDown(MotionEvent event) {
// Notified when a tap occurs.
return true;
}
@Override
public void onLongPress(MotionEvent e) {
// Notified when a long press occurs.
final String text = mBuffer.toString();
if (mListener != null) {
Log.d(TAG, "----> Long Click Occurs on TextView with ID: " + mWidget.getId() + "\n" +
"Text: " + text + "\n<----");
mListener.onLongClick(text);
}
}
@Override
public boolean onSingleTapConfirmed(MotionEvent event) {
// Notified when tap occurs.
final String linkText = getLinkText(mWidget, mBuffer, event);
LinkType linkType = LinkType.NONE;
if (Patterns.PHONE.matcher(linkText).matches()) {
linkType = LinkType.PHONE;
}
else if (Patterns.WEB_URL.matcher(linkText).matches()) {
linkType = LinkType.WEB_URL;
}
else if (Patterns.EMAIL_ADDRESS.matcher(linkText).matches()) {
linkType = LinkType.EMAIL_ADDRESS;
}
if (mListener != null) {
Log.d(TAG, "----> Tap Occurs on TextView with ID: " + mWidget.getId() + "\n" +
"Link Text: " + linkText + "\n" +
"Link Type: " + linkType + "\n<----");
mListener.onLinkClicked(linkText, linkType);
}
return false;
}
private String getLinkText(final TextView widget, final Spannable buffer, final MotionEvent event) {
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);
ClickableSpan[] link = buffer.getSpans(off, off, ClickableSpan.class);
if (link.length != 0) {
return buffer.subSequence(buffer.getSpanStart(link[0]),
buffer.getSpanEnd(link[0])).toString();
}
return "";
}
}
}
String str_links = "<a href='http://google.com'>Google</a><br /><a href='http://facebook.com'>Facebook</a>";
text_view.setText( Html.fromHtml( str_links ) );
text_view.setMovementMethod(new TextViewClickMovement(this, context));
J'espère que cela aide! Vous pouvez trouver le code ici .
J'utilise uniquement textView, et définit span pour url et gérer le clic.
J'ai trouvé une solution très élégante ici, sans lier - selon ce que je sais quelle partie de la corde je veux lier.
gérer le lien textview cliquer dans mon application Android
en kotlin:
fun linkify(view: TextView, url: String, context: Context) {
val text = view.text
val string = text.toString()
val span = ClickSpan(object : ClickSpan.OnClickListener {
override fun onClick() {
// handle your click
}
})
val start = string.indexOf(url)
val end = start + url.length
if (start == -1) return
if (text is Spannable) {
text.setSpan(span, start, end, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE)
text.setSpan(ForegroundColorSpan(ContextCompat.getColor(context, R.color.orange)),
start, end, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE)
} else {
val s = SpannableString.valueOf(text)
s.setSpan(span, start, end, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE)
s.setSpan(ForegroundColorSpan(ContextCompat.getColor(context, R.color.orange)),
start, end, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE)
view.text = s
}
val m = view.movementMethod
if (m == null || m !is LinkMovementMethod) {
view.movementMethod = LinkMovementMethod.getInstance()
}
}
class ClickSpan(private val mListener: OnClickListener) : ClickableSpan() {
override fun onClick(widget: View) {
mListener.onClick()
}
interface OnClickListener {
fun onClick()
}
}
et utilisation: linkify (yourTextView, urlString, context)