How to set the part of the text view is clickable

后端 未结 20 978
无人共我
无人共我 2020-11-22 01:29

I have the text \"Android is a Software stack\". In this text i want to set the \"stack\" text is clickable. in the sense if you click on t

相关标签:
20条回答
  • 2020-11-22 02:07

    You can use ClickableSpan as described in this post

    Sample code:

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

    Reference

    0 讨论(0)
  • 2020-11-22 02:07

    You can you this method to set the clickable value

    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
    }
    

    This is how to use it:

    TextView myTextView = findViewById(R.id.myTextView);
    setClickableString("stack", "Android is a Software stack", myTextView);
    
    0 讨论(0)
  • 2020-11-22 02:10

    Here is a Kotlin method to make parts of a TextView clickable:

    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
    }
    

    It can be called multiple times to create several links within a TextView:

    makeTextLink(myTextView, str, false, Color.RED, action = { Log.d("onClick", "link") })
    makeTextLink(myTextView, str1, true, null, action = { Log.d("onClick", "link1") })
    
    0 讨论(0)
  • 2020-11-22 02:11

    Complicated but universal solution on Kotlin

      /*
        * Receive Pair of Text and Action and set it clickable and appearing as link
        * */
    fun TextView.setClickableText(vararg textToSpanAndClickAction: Pair<String, (String) -> Unit>) {
        val builder = SpannableStringBuilder(text.toString())
    
        textToSpanAndClickAction.forEach { argPair ->
        val clickableSpan = object : ClickableSpan() {
            override fun onClick(widget: View) {
                argPair.second.invoke(argPair.first)
            }
        }
    
        this.text.toString().let { fullText ->
            val indexOfFirst = fullText.indexOf(argPair.first)
            val indexOfLast = indexOfFirst + argPair.first.length
            if (indexOfFirst < 0){
                //No match found
                return
            }else{
                builder.setSpan(
                    clickableSpan,
                    indexOfFirst,
                    indexOfLast,
                    Spanned.SPAN_EXCLUSIVE_EXCLUSIVE
                )
            }
        }
    }
    
    this.text = builder
        this.movementMethod = LinkMovementMethod.getInstance()
    }
    

    kotlin spannable

    0 讨论(0)
  • 2020-11-22 02:12

    I made this helper method in case someone need start and end position from a String.

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

    And here is how you use it

    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);
                    }
                });
    }
    
    0 讨论(0)
  • 2020-11-22 02:15

    I would suggest a different approach that I think requires less code and is more "localization-friendly".

    Supposing that your destination activity is called "ActivityStack", define in the manifest an intent filter for it with a custom scheme (e.g. "myappscheme") in AndroidManifest.xml:

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

    Define the TextView without any special tag (it is important to NOT use the "android:autoLink" tag, see: 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" />
    

    then use a link with custom scheme and host in the text of the TextView as (in String.xml):

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

    and "activate" the link with setMovementMethod() (in onCreate() for activities or onCreateView() for fragments):

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

    This will open the stack activity with a tap on the "stack" word.

    0 讨论(0)
提交回复
热议问题