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

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


当前回答

大胆的,

mySpannable.setSpan(new StyleSpan(Typeface.BOLD),termStart,termStop,Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);

其他回答

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

这是一个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)

这是一个Kotlin方法,使TextView的部分可点击:

private fun makeTextLink(textView: TextView, str: String, underlined: Boolean, color: Int?, action: (() -> Unit)? = null) {
    val spannableString = SpannableString(textView.text)
    val textColor = color ?: textView.currentTextColor
    val clickableSpan = object : ClickableSpan() {
        override fun onClick(textView: View) {
            action?.invoke()
        }
        override fun updateDrawState(drawState: TextPaint) {
            super.updateDrawState(drawState)
            drawState.isUnderlineText = underlined
            drawState.color = textColor
        }
    }
    val index = spannableString.indexOf(str)
    spannableString.setSpan(clickableSpan, index, index + str.length, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE)
    textView.text = spannableString
    textView.movementMethod = LinkMovementMethod.getInstance()
    textView.highlightColor = Color.TRANSPARENT
}

它可以被多次调用,在TextView中创建几个链接:

makeTextLink(myTextView, str, false, Color.RED, action = { Log.d("onClick", "link") })
makeTextLink(myTextView, str1, true, null, action = { Log.d("onClick", "link1") })

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

我会建议一种不同的方法,我认为这种方法需要更少的代码,而且更“本地化友好”。

假设你的目标活动被称为“ActivityStack”,在manifest中定义一个意图过滤器,使用一个自定义的方案(例如。“myappscheme”)

<activity
    android:name=".ActivityStack">
    <intent-filter>
        <action android:name="android.intent.action.VIEW" />
        <category android:name="android.intent.category.DEFAULT" />
        <data android:host="stack"/>
        <data android:scheme="myappscheme" />
    </intent-filter>
</activity>

定义没有任何特殊标签的TextView(重要的是不要使用"android:autoLink"标签,参见:https://stackoverflow.com/a/20647011/1699702):

<TextView
    android:id="@+id/stackView"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:text="@string/stack_string" />

然后在TextView的文本中使用带有自定义方案和主机的链接作为(在String.xml中):

<string name="stack_string">Android is a Software <a href="myappscheme://stack">stack</a></string>

和“激活”与setMovementMethod()(在onCreate()的活动或onCreateView()的片段链接):

TextView stack = findViewById(R.id.stackView);
stack.setMovementMethod(LinkMovementMethod.getInstance());

这将通过点击“stack”字打开堆栈活动。

您可以使用此方法设置可点击的值

public void setClickableString(String clickableValue, String wholeValue, TextView yourTextView){
    String value = wholeValue;
    SpannableString spannableString = new SpannableString(value);
    int startIndex = value.indexOf(clickableValue);
    int endIndex = startIndex + clickableValue.length();
    spannableString.setSpan(new ClickableSpan() {
                                @Override
                                public void updateDrawState(TextPaint ds) {
                                    super.updateDrawState(ds);
                                    ds.setUnderlineText(false); // <-- this will remove automatic underline in set span
                                }

                                @Override
                                public void onClick(View widget) {
                                    // do what you want with clickable value
                                }
                            }, startIndex, endIndex, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
    yourTextView.setText(spannableString);
    yourTextView.setMovementMethod(LinkMovementMethod.getInstance()); // <-- important, onClick in ClickableSpan won't work without this
}

下面是如何使用它:

TextView myTextView = findViewById(R.id.myTextView);
setClickableString("stack", "Android is a Software stack", myTextView);