我有文本“Android是一个软件堆栈”。在这个文本中,我想设置“堆栈”文本为可点击。所以,如果你点击它,它将重定向到一个新的活动(不在浏览器中)。

我试过了,但没有找到解决办法。


当前回答

我做了这个helper方法,以防有人需要从字符串中开始和结束位置。

public static TextView createLink(TextView targetTextView, String completeString,
    String partToClick, ClickableSpan clickableAction) {

    SpannableString spannableString = new SpannableString(completeString);

    // make sure the String is exist, if it doesn't exist
    // it will throw IndexOutOfBoundException
    int startPosition = completeString.indexOf(partToClick);
    int endPosition = completeString.lastIndexOf(partToClick) + partToClick.length();

    spannableString.setSpan(clickableAction, startPosition, endPosition,
        Spanned.SPAN_INCLUSIVE_EXCLUSIVE);

    targetTextView.setText(spannableString);
    targetTextView.setMovementMethod(LinkMovementMethod.getInstance());

    return targetTextView;
}

下面是你如何使用它

private void initSignUp() {
    String completeString = "New to Reddit? Sign up here.";
    String partToClick = "Sign up";
    ClickableTextUtil
        .createLink(signUpEditText, completeString, partToClick,
            new ClickableSpan() {
                @Override
                public void onClick(View widget) {
                    // your action
                    Toast.makeText(activity, "Start Sign up activity",
                        Toast.LENGTH_SHORT).show();
                }

                @Override
                public void updateDrawState(TextPaint ds) {
                    super.updateDrawState(ds);
                    // this is where you set link color, underline, typeface etc.
                    int linkColor = ContextCompat.getColor(activity, R.color.blumine);
                    ds.setColor(linkColor);
                    ds.setUnderlineText(false);
                }
            });
}

其他回答

我编写了一个例子来解决你的问题在Kotlin。

这是准则:

    val completeText = getString(R.string.terms_description)
    val textToFind = getString(R.string.show_terms)
    val spannableString: Spannable = SpannableString(completeText)
    val startFocus = completeText.indexOf(textToFind)
    val endFocus = startFocus + textToFind.length

    spannableString.setSpan(object: ClickableSpan() {
        override fun onClick(p0: View) {
            showMessage()
        }
    }, startFocus, endFocus, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE)
    show_terms.text = spannableString
    show_terms.movementMethod = LinkMovementMethod.getInstance();
    show_terms.highlightColor = Color.TRANSPARENT;

这是XML

    <CheckBox
            android:id="@+id/check_agree_terms"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"/>

    <TextView
            android:id="@+id/show_terms"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:textColorLink="@color/colorPrimary"
            android:layout_toEndOf="@id/check_agree_terms"/>

这就是它的样子

在这里输入图像描述

提供的解决方案相当不错。然而,我通常使用更简单的解决方案。

这是一个linkify效用函数

/**
 * Method is used to Linkify words in a TextView
 *
 * @param textView TextView who's text you want to change
 * @param textToLink The text to turn into a link
 * @param url   The url you want to send the user to
 */
fun linkify(textView: TextView, textToLink: String, url: String) {
    val pattern = Pattern.compile(textToLink)
    Linkify.addLinks(textView, pattern, url, { _, _, _ -> true })
    { _, _ -> "" }
}

使用这个函数非常简单。这里有一个例子

    // terms and privacy
    val tvTerms = findViewById<TextView>(R.id.tv_terms)
    val tvPrivacy = findViewById<TextView>(R.id.tv_privacy)
    Utils.linkify(tvTerms, resources.getString(R.string.terms),
            Constants.TERMS_URL)
    Utils.linkify(tvPrivacy, resources.getString(R.string.privacy),
            Constants.PRIVACY_URL)

你可以像本文中描述的那样使用ClickableSpan

示例代码:

TextView myTextView = new TextView(this);
String myString = "Some text [clickable]";
int i1 = myString.indexOf("[");
int i2 = myString.indexOf("]");
myTextView.setMovementMethod(LinkMovementMethod.getInstance());
myTextView.setText(myString, BufferType.SPANNABLE);
Spannable mySpannable = (Spannable)myTextView.getText();
ClickableSpan myClickableSpan = new ClickableSpan() {
   @Override
   public void onClick(View widget) { /* do something */ }
};
mySpannable.setSpan(myClickableSpan, i1, i2 + 1, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);

参考

android.text.style.ClickableSpan可以解决你的问题。

SpannableString ss = new SpannableString("Android is a Software stack");
ClickableSpan clickableSpan = new ClickableSpan() {
    @Override
    public void onClick(View textView) {
        startActivity(new Intent(MyActivity.this, NextActivity.class));
    }
    @Override
    public void updateDrawState(TextPaint ds) {
        super.updateDrawState(ds);
        ds.setUnderlineText(false);
    }
};
ss.setSpan(clickableSpan, 22, 27, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);

TextView textView = (TextView) findViewById(R.id.hello);
textView.setText(ss);
textView.setMovementMethod(LinkMovementMethod.getInstance());
textView.setHighlightColor(Color.TRANSPARENT);

在XML:

<TextView 
  ...
  android:textColorLink="@drawable/your_selector"
/>

Java解决方案(更新2022年)

特点:

允许多个点击时,有重复的词。 可以为每个重复的单词量身定制特定的命令。

我以daler445的代码为基础,允许对重复的单词使用多个可单击的命令。

在Java课上:

public class MainActivity extends AppCompatActivity {
    SharedPreferences sp;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        sp = getSharedPreferences("MyUserPrefs", Context.MODE_PRIVATE);
        SharedPreferences.Editor editor = sp.edit();

        TextView fulltext = (TextView) findViewById(R.id.fulltext);

        //replace setText("") to setText("Android is a Software stack") for his case
        fulltext.setText("Search [1] this full [1] text with repeated strings. Search [2] Search [3] full [2] full [3]");

        List<Pair<String, View.OnClickListener>> links = new ArrayList<>();

        //replace "Search" with "stack" for his case
        String stringtohyperlink = "Search";
        String stringtohyperlink2 = "full";

        links.add(new Pair<>(stringtohyperlink, new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                String position = sp.getString("position","0");
                if (position.equals("1")) {
                    Toast.makeText(MainActivity.this, "Search 1 has been Clicked.", Toast.LENGTH_SHORT).show();
                    editor.putString("position","0");
                    editor.apply();
                }
                if (position.equals("2")) {
                    Toast.makeText(MainActivity.this, "Search 2 has been Clicked.", Toast.LENGTH_SHORT).show();
                    editor.putString("position","0");
                    editor.apply();
                }
                if (position.equals("3")) {
                    Toast.makeText(MainActivity.this, "Search 3 has been Clicked.", Toast.LENGTH_SHORT).show();
                    editor.putString("position","0");
                    editor.apply();
                }
            }
        }));

        links.add(new Pair<>(stringtohyperlink2, new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                String position = sp.getString("position","0");
                if (position.equals("1")) {
                    Toast.makeText(MainActivity.this, "full 1 has been Clicked.", Toast.LENGTH_SHORT).show();
                    editor.putString("position","0");
                    editor.apply();
                }
                if (position.equals("2")) {
                    Toast.makeText(MainActivity.this, "full 2 has been Clicked.", Toast.LENGTH_SHORT).show();
                    editor.putString("position","0");
                    editor.apply();
                }
                if (position.equals("3")) {
                    Toast.makeText(MainActivity.this, "full 3 has been Clicked.", Toast.LENGTH_SHORT).show();
                    editor.putString("position","0");
                    editor.apply();
                }
            }
        }));


        makeLinks(fulltext, links);


    }

    public void makeLinks(TextView textView, List<Pair<String, View.OnClickListener>> links) {
        SpannableString spannableString = new SpannableString(textView.getText().toString());

        int startIndexState = -1;
        SharedPreferences.Editor editor = sp.edit();

        for (Pair<String, View.OnClickListener> link : links) {
            ClickableSpan clickableSpan = new ClickableSpan() {
                @Override
                public void onClick(@NonNull View widget) {
                    editor.putString("position","1");
                    editor.apply();

                    widget.invalidate();
                    assert link.second != null;
                    link.second.onClick(widget);
                }
            };
            ClickableSpan clickableSpan2 = new ClickableSpan() {
                @Override
                public void onClick(@NonNull View widget) {
                    editor.putString("position","2");
                    editor.apply();

                    widget.invalidate();
                    assert link.second != null;
                    link.second.onClick(widget);
                }
            };

            ClickableSpan clickableSpan3 = new ClickableSpan() {
                @Override
                public void onClick(@NonNull View widget) {
                    editor.putString("position","3");
                    editor.apply();

                    widget.invalidate();
                    assert link.second != null;
                    link.second.onClick(widget);
                }
            };
            //... This only allows for 3 repeated words
            //... Add more of it, if there are more repeated words.

            assert link.first != null;
            int startIndexOfLink = textView.getText().toString().indexOf(link.first, startIndexState + 1);
            spannableString.setSpan(clickableSpan, startIndexOfLink, startIndexOfLink + link.first.length(), Spanned.SPAN_EXCLUSIVE_INCLUSIVE);

            int startIndexOfLink2 = textView.getText().toString().indexOf(link.first, startIndexOfLink + 1);
            if (startIndexOfLink2 != -1) {
                spannableString.setSpan(clickableSpan2, startIndexOfLink2, startIndexOfLink2 + link.first.length(), Spanned.SPAN_EXCLUSIVE_INCLUSIVE);
            }

            int startIndexOfLink3 = textView.getText().toString().indexOf(link.first, startIndexOfLink2 + 1);
            if (startIndexOfLink3 != -1) {
                spannableString.setSpan(clickableSpan3, startIndexOfLink3, startIndexOfLink3 + link.first.length(), Spanned.SPAN_EXCLUSIVE_INCLUSIVE);
            }
            //... This only allows for 3 repeated words
            //... Add more of it, if there are more repeated words.

            textView.setMovementMethod(LinkMovementMethod.getInstance());
            textView.setText(spannableString, TextView.BufferType.SPANNABLE);
        }
    }
}

在xml

  <TextView
        android:id="@+id/fulltext"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="TextView"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent" />

Demo