How to click or tap on a TextView text on different words?

血红的双手。 提交于 2019-11-27 00:40:30

I finally figured it out how to have multiple clickable parts in a TextView. It is important that they all have their own ClickableSpan! That is where I went wrong the first time testing it. If they have the same ClickableSpan instance, only the last set span is remembered.

I created a String with the required clickable area's surrounded by "[" and "]".

String sentence = "this is [part 1] and [here another] and [another one]";

and here is the set TextView, the setMovementMehthod is also mandatory:

textView.setMovementMethod(LinkMovementMethod.getInstance());
textView.setText(addClickablePart(sentence), BufferType.SPANNABLE);

I have created this function, which will handle the creation of the clickable area's:

private SpannableStringBuilder addClickablePart(String str) {
    SpannableStringBuilder ssb = new SpannableStringBuilder(str);

    int idx1 = str.indexOf("[");
    int idx2 = 0;
    while (idx1 != -1) {
        idx2 = str.indexOf("]", idx1) + 1;

        final String clickString = str.substring(idx1, idx2);
        ssb.setSpan(new ClickableSpan() {

            @Override
            public void onClick(View widget) {
                Toast.makeText(getView().getContext(), clickString,
                        Toast.LENGTH_SHORT).show();
            }
        }, idx1, idx2, 0);
        idx1 = str.indexOf("[", idx2);
    }

    return ssb;
}
phyzalis

Based on Boy's response (and thank you for your response which helped me a lot), here is another way I implemented it without this '[' and ']' chars using an inner class to describe clickable words :

import java.util.List;

import android.content.Context;
import android.text.SpannableStringBuilder;
import android.text.method.LinkMovementMethod;
import android.text.style.ClickableSpan;
import android.util.AttributeSet;
import android.widget.TextView;

/**
 * Defines a TextView widget where user can click on different words to see different actions
 *
 */
public class ClickableTextView extends TextView {

    public ClickableTextView(Context context) {
        super(context);
    }

    public ClickableTextView(Context context, AttributeSet attrs) {
        super(context, attrs);
    }

    public ClickableTextView(Context context, AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);
    }

    public void setTextWithClickableWords(String text, List<ClickableWord> clickableWords) {
        setMovementMethod(LinkMovementMethod.getInstance());
        setText(addClickablePart(text, clickableWords), BufferType.SPANNABLE);
    }

    private SpannableStringBuilder addClickablePart(String str, List<ClickableWord> clickableWords) {
        SpannableStringBuilder ssb = new SpannableStringBuilder(str);

        for (ClickableWord clickableWord : clickableWords) {
            int idx1 = str.indexOf(clickableWord.getWord());
            int idx2 = 0;
            while (idx1 != -1) {
                idx2 = idx1 + clickableWord.getWord().length();
                ssb.setSpan(clickableWord.getClickableSpan(), idx1, idx2, 0);
                idx1 = str.indexOf(clickableWord.getWord(), idx2);
            }
        }

        return ssb;
    }

    public static class ClickableWord {
        private String word;
        private ClickableSpan clickableSpan;

        public ClickableWord(String word, ClickableSpan clickableSpan) {
            this.word = word;
            this.clickableSpan = clickableSpan;
        }

        /**
         * @return the word
         */
        public String getWord() {
            return word;
        }

        /**
         * @return the clickableSpan
         */
        public ClickableSpan getClickableSpan() {
            return clickableSpan;
        }
    }
}

Hope this may help someone

EDIT : how to change link color and remove underline:

Create and use your own implementation of ClickableSpan like this :

//a version of ClickableSpan without the underline
public static class NoUnderlineClickableSpan extends ClickableSpan {
    private int color = -1;

    public void setColor(int color) {
        this.color = color;
    }

    @Override
    public void updateDrawState(TextPaint ds) {
        ds.setUnderlineText(false);
        if (this.color != -1) {
            ds.setColor(this.color);
        }
    }
}

It's much simpler to use HTML with links in TextView than creating multiple TextViews, taking care about layout, listeners etc.

In your activity or fragment:

    TextView mText = (TextView) findViewById(R.id.text_linkified);
    mText.setText(Html.fromHtml("Open <a href='myapp://my-activity'>My Activity</a> or" +
            " <a href='myapp://other-activity'>Other Activity</a>"));
    mText.setMovementMethod(LinkMovementMethod.getInstance());

In manifest

    <activity android:name=".MyActivity">
        <intent-filter>
            <action android:name="android.intent.action.VIEW" />
            <category android:name="android.intent.category.DEFAULT"/>
            <data android:scheme="myapp" android:host="my-activity"/>
        </intent-filter>
    </activity>
    <activity android:name=".MyOtherActivity">
        <intent-filter>
            <action android:name="android.intent.action.VIEW" />
            <category android:name="android.intent.category.DEFAULT"/>
            <data android:scheme="myapp" android:host="other-activity" />
        </intent-filter>
    </activity>

I recommend this library: https://github.com/klinker24/Android-TextView-LinkBuilder

it fits your requirement very well.

A quick overview:

copied form project's readme:

  • Specify long and short click actions of a specific word within your TextView
  • Provide user feedback by highlighting the text when the user touches it Match single strings or use a regular expression to set clickable links to any text conforming to that pattern
  • Change the color of the linked text
  • Modify the transparency of the text's highlighting when the user touches it
  • Set whether or not you want the text underlined

The main advantage to using this library over TextView's autolink functionality is that you can link anything, not just web address, emails, and phone numbers. It also provides color customization and touch feedback.

In ClickableTextView implementation, what happens if string got a word with repeated ? suppose for example string is "I'm clickable and also this is clickable" then both the strings should be changed to Spannable string but it fails it that scenario, only one will be changed to spannable string.

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!