wake-up-neo.com

textview-Link in meiner Android-App bearbeiten

Ich rendere derzeit HTML-Eingaben in einer Textansicht wie folgt:

tv.setText(Html.fromHtml("<a href='test'>test</a>"));

Der angezeigte HTML-Code wird mir über eine externe Ressource zur Verfügung gestellt, sodass ich die Dinge nicht beliebig ändern kann. Natürlich kann ich etwas Regex dazu verwenden, den HTML-Code zu manipulieren, um den href-Wert beispielsweise in etwas anderes zu ändern.

Ich möchte in der Lage sein, einen Link-Klick direkt in der App zu handhaben, anstatt dass der Link ein Browser-Fenster öffnet. Ist das überhaupt erreichbar? Ich vermute, es wäre möglich, das Protokoll des href-Werts auf "myApp: //" zu setzen und dann etwas zu registrieren, das meine App mit diesem Protokoll umgehen lässt. Wenn dies wirklich der beste Weg ist, würde ich gerne wissen, wie das gemacht wird, aber ich hoffe, es gibt einen einfacheren Weg, um einfach zu sagen: "Wenn in dieser Textansicht ein Link angeklickt wird, möchte ich ein Ereignis ansprechen, das aufkommt der href-Wert der Verknüpfung als Eingabeparameter "

137
David Hedlund

Fast ein Jahr später kommt es auf eine andere Art und Weise, in der ich mein spezielles Problem gelöst habe. Da ich wollte, dass der Link von meiner eigenen App verarbeitet wird, gibt es eine etwas einfachere Lösung.

Neben dem Standard-Intent-Filter lasse ich einfach zu, dass meine Zielaktivität auf ACTION_VIEW Intents hört, und insbesondere auf diejenigen mit dem Schema com.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>

Das bedeutet, dass Links, die mit com.package.name:// beginnen, von meiner Aktivität bearbeitet werden.

Also muss ich nur eine URL erstellen, die die Informationen enthält, die ich vermitteln möchte:

com.package.name://action-to-perform/id-that-might-be-needed/

In meiner Zielaktivität kann ich diese Adresse abrufen:

Uri data = getIntent().getData();

In meinem Beispiel könnte ich einfach data auf Nullwerte überprüfen, denn wenn es nicht Null ist, weiß ich, dass es mit einem solchen Link aufgerufen wurde. Von dort extrahiere ich die erforderlichen Anweisungen aus der URL, um die entsprechenden Daten anzeigen zu können.

177
David Hedlund

Eine andere Möglichkeit: Sie leihen sich ein wenig von Linkify, können jedoch Ihre Handhabung anpassen.

Kundenspezifische Klasse:

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();
    }
}

Helferfunktion:

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());
    }
}

Verwendungszweck:

 clickify(textView, clickText,new ClickSpan.OnClickListener()
     {
        @Override
        public void onClick() {
            // do something
        }
    });
61
Jonathan S.

wenn in der Textansicht mehrere Links vorhanden sind. Zum Beispiel hat textview "https: //" und "tel no". Wir können die LinkMovement-Methode anpassen und Klicks für Wörter basierend auf einem Muster verarbeiten. Im Anhang befindet sich die angepasste Link Movement-Methode.

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;
}

Dies sollte auf folgende Weise aus der Textansicht aufgerufen werden:

textViewObject.setMovementMethod(CustomLinkMovementMethod.getInstance(context));
52
Arun

Hier ist eine allgemeinere Lösung, die auf der Antwort von @Arun basiert

public abstract class TextViewLinkHandler extends LinkMovementMethod {

    public boolean onTouchEvent(TextView widget, Spannable buffer, MotionEvent event) {
        if (event.getAction() != MotionEvent.ACTION_UP)
            return super.onTouchEvent(widget, buffer, 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);

        URLSpan[] link = buffer.getSpans(off, off, URLSpan.class);
        if (link.length != 0) {
            onLinkClick(link[0].getURL());
        }
        return true;
    }

    abstract public void onLinkClick(String url);
}

Um es zu verwenden, implementieren Sie einfach onLinkClick der Klasse TextViewLinkHandler. Zum Beispiel:

    textView.setMovementMethod(new TextViewLinkHandler() {
        @Override
        public void onLinkClick(String url) {
            Toast.makeText(textView.getContext(), url, Toast.LENGTH_SHORT);
        }
    });
34
ruX

es ist sehr einfach, diese Zeile zu Ihrem Code hinzuzufügen:

tv.setMovementMethod(LinkMovementMethod.getInstance());
10
jonathan

Lösung

Ich habe eine kleine Klasse implementiert, mit deren Hilfe Sie lange Klicks auf TextView selbst und Taps auf die Links in der TextView ausführen können.

Layout

TextView Android:id="@+id/text"
                Android:layout_width="wrap_content"
                Android:layout_height="wrap_content"
                Android:autoLink="all"/>

TextViewClickMovement.Java

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 "";
        }
    }
}

Verwendungszweck

TextView tv = (TextView) v.findViewById(R.id.textview);
tv.setText(Html.fromHtml("<a href='test'>test</a>"));
textView.setMovementMethod(new TextViewClickMovement(this, context));

Links

Hoffe das hilft! Sie finden den Code hier .

4
Victor Apoyan

Nur um eine alternative Lösung mit einer von mir erstellten Bibliothek gemeinsam zu nutzen. Mit Textoo kann dies wie folgt erreicht werden:

TextView locNotFound = Textoo
    .config((TextView) findViewById(R.id.view_location_disabled))
    .addLinksHandler(new LinksHandler() {
        @Override
        public boolean onClick(View view, String url) {
            if ("internal://settings/location".equals(url)) {
                Intent locSettings = new Intent(Android.provider.Settings.ACTION_LOCATION_SOURCE_SETTINGS);
                startActivity(locSettings);
                return true;
            } else {
                return false;
            }
        }
    })
    .apply();

Oder mit dynamischem HTML-Quelltext:

String htmlSource = "Links: <a href='http://www.google.com'>Google</a>";
Spanned linksLoggingText = Textoo
    .config(htmlSource)
    .parseHtml()
    .addLinksHandler(new LinksHandler() {
        @Override
        public boolean onClick(View view, String url) {
            Log.i("MyActivity", "Linking to google...");
            return false; // event not handled.  Continue default processing i.e. link to google
        }
    })
    .apply();
textView.setText(linksLoggingText);
3
PH88

wer mehr Möglichkeiten sucht, ist hier eine

// Set text within a `TextView`
TextView textView = (TextView) findViewById(R.id.textView);
textView.setText("Hey @sarah, where did @jim go? #lost");
// Style clickable spans based on pattern
new PatternEditableBuilder().
    addPattern(Pattern.compile("\\@(\\w+)"), Color.BLUE,
       new PatternEditableBuilder.SpannableClickedListener() {
        @Override
        public void onSpanClicked(String text) {
            Toast.makeText(MainActivity.this, "Clicked username: " + text,
                Toast.LENGTH_SHORT).show();
        }
}).into(textView);

RESOURCE:CodePath

2
Dasser Basyouni
public static void setTextViewFromHtmlWithLinkClickable(TextView textView, String text) {
    Spanned result;
    if (Android.os.Build.VERSION.SDK_INT >= Android.os.Build.VERSION_CODES.N) {
        result = Html.fromHtml(text, Html.FROM_HTML_MODE_LEGACY);
    } else {
        result = Html.fromHtml(text);
    }
    textView.setText(result);
    textView.setMovementMethod(LinkMovementMethod.getInstance());
}
2
Kai Wang

Diese Antwort erweitert Jonathan S 'hervorragende Lösung:

Sie können die folgende Methode verwenden, um Links aus dem Text zu extrahieren:

private static ArrayList<String> getLinksFromText(String text) {
        ArrayList links = new ArrayList();

        String regex = "\(?\b((http|https)://www[.])[-A-Za-z0-9+&@#/%?=~_()|!:,.;]*[-A-Za-z0-9+&@#/%=~_()|]";
        Pattern p = Pattern.compile(regex);
        Matcher m = p.matcher(text);
        while (m.find()) {
            String urlStr = m.group();
            if (urlStr.startsWith("(") && urlStr.endsWith(")")) {
                urlStr = urlStr.substring(1, urlStr.length() - 1);
            }
            links.add(urlStr);
        }
        return links;
    }

Damit kann einer der Parameter in der clickify()-Methode entfernt werden:

public static void clickify(TextView view,
                                final ClickSpan.OnClickListener listener) {

        CharSequence text = view.getText();
        String string = text.toString();


        ArrayList<String> linksInText = getLinksFromText(string);
        if (linksInText.isEmpty()){
            return;
        }


        String clickableText = linksInText.get(0);
        ClickSpan span = new ClickSpan(listener,clickableText);

        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());
        }
    }

Einige Änderungen am ClickSpan:

public static class ClickSpan extends ClickableSpan {

        private String mClickableText;
        private OnClickListener mListener;

        public ClickSpan(OnClickListener listener, String clickableText) {
            mListener = listener;
            mClickableText = clickableText;
        }

        @Override
        public void onClick(View widget) {
            if (mListener != null) mListener.onClick(mClickableText);
        }

        public interface OnClickListener {
            void onClick(String clickableText);
        }
    }

Jetzt können Sie den Text einfach in der Textansicht festlegen und dann einen Listener hinzufügen:

TextViewUtils.clickify(textWithLink,new TextUtils.ClickSpan.OnClickListener(){

@Override
public void onClick(String clickableText){
  //action...
}

});
1
W.K.S

Ich habe die Farbe von TextView zu Blau geändert, indem ich beispielsweise Folgendes verwendet: 

Android:textColor="#3399FF"

in der XML-Datei. Wie man es unterstrichen macht, wird erklärt hier

Verwenden Sie dann die onClick-Eigenschaft, um eine Methode anzugeben (Ich denke, Sie könnten setOnClickListener(this) auch auf andere Weise aufrufen), z.

myTextView.setOnClickListener(new OnClickListener() {
public void onClick(View v) {
    doSomething();
}
});

In dieser Methode kann ich alles normal machen, z. B. eine Absicht starten. Beachten Sie, dass Sie immer noch das normale myTextView.setMovementMethod(LinkMovementMethod.getInstance()); tun müssen, wie in der onCreate () -Methode Ihrer Aktivität.

1
Tyler Collier

Die beste Art und Weise, die ich benutzt habe und es hat immer für mich funktioniert

Android:autoLink="web"
1
Rohit Mandiwal

Beispiel: Angenommen, Sie haben Text in Textansicht festgelegt und möchten einen Link für einen bestimmten Textausdruck angeben: "Klicken Sie auf #facebook, um Sie zu facebook.com zu bringen."

In Layout xml: 

<TextView
            Android:id="@+id/testtext"
            Android:layout_width="wrap_content"
            Android:layout_height="wrap_content" />

In Aktivität:

String text  =  "Click on #facebook will take you to facebook.com";
tv.setText(text);
Pattern tagMatcher = Pattern.compile("[#]+[A-Za-z0-9-_]+\\b");
String newActivityURL = "content://ankit.testactivity/";
Linkify.addLinks(tv, tagMatcher, newActivityURL);

Erstellen Sie auch einen Tag-Provider als:

public class TagProvider extends ContentProvider {

    @Override
    public int delete(Uri arg0, String arg1, String[] arg2) {
        // TODO Auto-generated method stub
        return 0;
    }

    @Override
    public String getType(Uri arg0) {
        return "vnd.Android.cursor.item/vnd.cc.tag";
    }

    @Override
    public Uri insert(Uri arg0, ContentValues arg1) {
        // TODO Auto-generated method stub
        return null;
    }

    @Override
    public boolean onCreate() {
        // TODO Auto-generated method stub
        return false;
    }

    @Override
    public Cursor query(Uri arg0, String[] arg1, String arg2, String[] arg3,
                        String arg4) {
        // TODO Auto-generated method stub
        return null;
    }

    @Override
    public int update(Uri arg0, ContentValues arg1, String arg2, String[] arg3) {
        // TODO Auto-generated method stub
        return 0;
    }

}

In der Manifestdatei machen Sie als Eintrag für Provider- und Testaktivität Folgendes:

<provider
    Android:name="ankit.TagProvider"
    Android:authorities="ankit.testactivity" />

<activity Android:name=".TestActivity"
    Android:label = "@string/app_name">
    <intent-filter >
        <action Android:name="Android.intent.action.VIEW" />
        <category Android:name="Android.intent.category.DEFAULT" />
        <data Android:mimeType="vnd.Android.cursor.item/vnd.cc.tag" />
    </intent-filter>
</activity>

Wenn Sie jetzt auf #facebook klicken, wird testactivtiy aufgerufen. Und in der Testaktivität können Sie die Daten erhalten als:

Uri uri = getIntent().getData();
0
Ankit Adlakha