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

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


当前回答

你可以像本文中描述的那样使用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);

参考

其他回答

对于kotlin使用这个扩展

fun TextView.makeLinks(vararg links: Pair<String, View.OnClickListener>) {
val spannableString = SpannableString(this.text)
for (link in links) {
    val clickableSpan = object : ClickableSpan() {
        override fun onClick(view: View) {
            Selection.setSelection((view as TextView).text as Spannable, 0)
            view.invalidate()
            link.second.onClick(view)
        }
    }
    val startIndexOfLink = this.text.toString().indexOf(link.first)
    spannableString.setSpan(
        clickableSpan, startIndexOfLink, startIndexOfLink + link.first.length,
        Spanned.SPAN_EXCLUSIVE_EXCLUSIVE
    )
    spannableString.setSpan(
        ForegroundColorSpan(Color.parseColor("#46C2CC")),
        startIndexOfLink,
        startIndexOfLink + link.first.length,
        Spanned.SPAN_EXCLUSIVE_EXCLUSIVE
    )
}
this.movementMethod =
    LinkMovementMethod.getInstance() // without LinkMovementMethod, link can not click
this.setText(spannableString, TextView.BufferType.SPANNABLE)

}

像这样调用它

binding.agreeText.makeLinks(Pair(getString(R.string.terms_conditionsClick),View.OnClickListener {
        startActivity(TermsAndConditionActivity.getIntent(this))
    }))

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

您可以使用示例代码。您希望了解关于ClickableSpan的详细信息。请检查这份文件

  SpannableString myString = new SpannableString("This is example");
            
            ClickableSpan clickableSpan = new ClickableSpan() {
                    @Override
                    public void onClick(View textView) {
                        ToastUtil.show(getContext(),"Clicked Smile ");
                    }
                };
        
        //For Click
         myString.setSpan(clickableSpan,startIndex,lastIndex,Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
        
        //For UnderLine
         myString.setSpan(new UnderlineSpan(),startIndex,lastIndex,0);
        
        //For Bold
        myString.setSpan(new StyleSpan(Typeface.BOLD),startIndex,lastIndex,0);
        
        //Finally you can set to textView. 
        
        TextView textView = (TextView) findViewById(R.id.txtSpan);
        textView.setText(myString);
        textView.setMovementMethod(LinkMovementMethod.getInstance());

我编写了一个例子来解决你的问题在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"/>

这就是它的样子

在这里输入图像描述

使用URLSpan类获取url

val spans: Array<URLSpan> = result.getSpans(0, result.length, URLSpan::class.java)

方法

fun TextView.createClickable(string: String, action:(String)->Unit ) {
      text = HtmlCompat.fromHtml(string, HtmlCompat.FROM_HTML_MODE_LEGACY)
      val result = SpannableString(text)
      val spans = result.getSpans(0, result.length, URLSpan::class.java)
      for (span in spans) {
          val link:Pair<String, View.OnClickListener> = Pair(span.url, View.OnClickListener {
              action(span.url)
          })
          val start = result.getSpanStart(span)
          val end = result.getSpanEnd(span)
          val flags = result.getSpanFlags(span)
          result.removeSpan(span)
          val clickableSpan: ClickableSpan = object : ClickableSpan() {
              override fun onClick(textView: View) {
                  textView.invalidate()
                  link.second.onClick(textView)
              }
              override fun updateDrawState(textPaint: TextPaint) {
                  super.updateDrawState(textPaint)
                  textPaint.isUnderlineText = false
              }
          }
          result.setSpan(clickableSpan, start, end, flags)
          this.movementMethod = LinkMovementMethod.getInstance()
          this.setText(result, TextView.BufferType.SPANNABLE)
      }
  }

Use

示例文本:Android是一个软件堆栈,它非常棒

包装你的可点击的文本内锚标签

比如:Android是一个软件<a href='https://example.com/stack'> Stack </a>和它' <a href='https://example.com/awesome'> Awesome </a>。

 val str = "Android is a Software <a href='https://example.com/stack'> Stack </a> and it' <a href='https://example.com/awesome'> Awesome </a>."

textView.createClickable(str) {
    when(it) {
        "https://example.com/stack"->{
  startActivity(Intent(this,StackActivity::class.java))
                  }
        "https://example.com/awesom"->{
            startActivity(Intent(this,AwesomeActivity::class.java))
        }
    }
}