Multiple Clickable links in TextView on Android

后端 未结 8 739
无人共我
无人共我 2020-12-14 07:16

I\'m trying to add multiple links in a textview similar to what Google & Flipboard has done below with their Terms and conditions AND Privacy Po

相关标签:
8条回答
  • 2020-12-14 07:51

    Here's my solution:

    First we need to have clickable links in our TextView:

    1. Here's my TextView in the xml layout, do not add any links handling parameters.

      <TextView
              android:id="@+id/sign_up_privacy"
              android:layout_width="wrap_content"
              android:layout_height="wrap_content"
              android:text="@string/terms_and_privacy"/>
      
    2. In strings file, I added the resource text with html tags

      <string name="terms_and_privacy">By signing up you agree to our <a href="terms:">Terms of Service</a> and <a href="privacy:">Privacy Policy.</a></string>
      
    3. In onCreateView set LinkMovementMethod to the TextView

      TextView privacyTextView = (TextView) root.findViewById(R.id.sign_up_privacy);
      privacyTextView.setMovementMethod(LinkMovementMethod.getInstance());
      

    Now the TextView links are clickable.

    Second, We need to Handle these clicks:

    1. In my Manifest file, I added intent-filter for "terms" and "privacy" and Single Instance Launch Mode

      <activity
                  android:name=".MyActivity"
                  android:launchMode="singleInstance">
                  <intent-filter>
                      <category android:name="android.intent.category.DEFAULT"/>
                      <action android:name="android.intent.action.VIEW"/>
      
                      <data android:scheme="terms"/>
                      <data android:scheme="privacy"/>
                  </intent-filter>
              </activity>
      
    2. In MyActivity, override onNewIntent to catch privacy and terms intents

      @Override
          protected void onNewIntent(Intent intent)
          {
              if (intent.getScheme().equalsIgnoreCase(getString("terms")))
              {
                  //handle terms clicked
              }
              else if (intent.getScheme().equalsIgnoreCase(getString("privacy")))
              {
                  //handle privacy clicked
              }
              else
              {
                  super.onNewIntent(intent);
              }
          }
      
    0 讨论(0)
  • 2020-12-14 07:59

    The best way to do this is with string file

    In string.xml

    <string name="agree_to_terms">I agree to the %1$s and %2$s</string>
    <string name="terms_of_service">Terms of Service</string>
    <string name="privacy_policy">Privacy Policy</string>
    

    In onCreateView call below method

    private void setTermsAndCondition() {
        String termsOfServicee = getString(R.string.terms_of_service);
        String privacyPolicy = getString(R.string.privacy_policy);
        String completeString = getString(R.string.agree_to_terms, termsOfServicee,privacyPolicy);
        int startIndex = completeString.indexOf(termsOfServicee);
        int endIndex = startIndex + termsOfServicee.length();
        int startIndex2 = completeString.indexOf(privacyPolicy);
        int endIndex2 = startIndex2 + privacyPolicy.length();
        SpannableStringBuilder spannableStringBuilder = new SpannableStringBuilder(completeString);
        ClickableSpan clickOnTerms = new ClickableSpan() {
            @Override
            public void onClick(View widget) {
                Toast.makeText(this, "click on terms of service", Toast.LENGTH_SHORT).show();
            }
    
            @Override
            public void updateDrawState(TextPaint ds) {
                ds.setColor(ContextCompat.getColor(this, R.color.blue));
    
            }
        };
        ClickableSpan clickOnPrivacy = new ClickableSpan() {
            @Override
            public void onClick(View widget) {
                Toast.makeText(this, "click on privacy policy", Toast.LENGTH_SHORT).show();
            }
    
            @Override
            public void updateDrawState(TextPaint ds) {
                ds.setColor(ContextCompat.getColor(this, R.color.blue));
    
            }
        };
        spannableStringBuilder.setSpan(clickOnTerms, startIndex, endIndex, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
        spannableStringBuilder.setSpan(clickOnPrivacy, startIndex2, endIndex2, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
        yourTextView.setText(spannableStringBuilder);
        yourTextView.setMovementMethod(LinkMovementMethod.getInstance());
    }
    
    0 讨论(0)
  • 2020-12-14 08:01

    You can use Linkify (android.text.Spannable,java.util.regex.Pattern,java.lang.String)

    String termsAndConditions = getResources().getString(R.string.terms_and_conditions);
    String privacyPolicy = getResources().getString(R.string.privacy_policy);
    
    legalDescription.setText(
        String.format(
            getResources().getString(R.string.message),
            termsAndConditions,
            privacyPolicy)
    );
    legalDescription.setMovementMethod(LinkMovementMethod.getInstance());
    
    Pattern termsAndConditionsMatcher = Pattern.compile(termsAndConditions);
    Linkify.addLinks(legalDescription, termsAndConditionsMatcher, "terms:");
    
    Pattern privacyPolicyMatcher = Pattern.compile(privacyPolicy);
    Linkify.addLinks(legalDescription, privacyPolicyMatcher, "privacy:");
    

    and then you can use the scheme to start an activity for example by adding the scheme in the AndroidManifest:

    <intent-filter>
        <category android:name="android.intent.category.DEFAULT" />
        <action android:name="android.intent.action.VIEW" />
        <data android:scheme="terms" />
        <data android:scheme="privacy" />
    </intent-filter>
    

    If you want to do a custom action, you can set the intent-filter to your current activity, which will have a singleTop launchmode.

    This will cause onNewIntent to be fired where can make your custom actions:

    @Override
    protected void onNewIntent(final Intent intent) {
     ...
      if (intent.getScheme().equals(..)) {
        ..
      }
    }
    
    0 讨论(0)
  • 2020-12-14 08:04
    
    private fun customTextView(view: TextView) {
    
            //I agree to the Terms of service & Privacy Policy,
            val spanTxt = SpannableStringBuilder(
                "I agree to the ")
            spanTxt.append("Terms of service")
            spanTxt.setSpan(object : ClickableSpan() {
                override fun onClick(widget: View) {
                 
                    toast("Terms of service link clicked")
    
                }
            }, spanTxt.length - "Term of services".length, spanTxt.length, 0)
            spanTxt.append(" and")
            spanTxt.append(" Privacy Policy")
            spanTxt.setSpan(object : ClickableSpan() {
                override fun onClick(widget: View) {
    
                    toast("Privacy Policy link clicked")
    
                }
            }, spanTxt.length - " Privacy Policy".length, spanTxt.length, 0)
            view.movementMethod = LinkMovementMethod.getInstance()
            view.setText(spanTxt, TextView.BufferType.SPANNABLE)
        }
    
    0 讨论(0)
  • 2020-12-14 08:05

    An easy fix for this would be to use multiple labels. One for each link and one for the text.

    [TermsOfServiceLabel][andLabel][PrivacyPolicy]
    

    Or is it necessary that you only use one label?

    0 讨论(0)
  • 2020-12-14 08:12

    I think that I'm a little late to share this, but I have achieved the same using SpannableStringBuilder.

    Simply initialize the TextView that you want to add 2 or more listeners and then pass that to the following method that I have created:

    private void customTextView(TextView view) {
            SpannableStringBuilder spanTxt = new SpannableStringBuilder(
                    "I agree to the ");
            spanTxt.append("Term of services");
            spanTxt.setSpan(new ClickableSpan() {
                @Override
                public void onClick(View widget) {
                    Toast.makeText(getApplicationContext(), "Terms of services Clicked",
                            Toast.LENGTH_SHORT).show();
                }
            }, spanTxt.length() - "Term of services".length(), spanTxt.length(), 0);
            spanTxt.append(" and");
            spanTxt.setSpan(new ForegroundColorSpan(Color.BLACK), 32, spanTxt.length(), 0);
            spanTxt.append(" Privacy Policy");
            spanTxt.setSpan(new ClickableSpan() {
                @Override
                public void onClick(View widget) {
                    Toast.makeText(getApplicationContext(), "Privacy Policy Clicked",
                            Toast.LENGTH_SHORT).show();
                }
            }, spanTxt.length() - " Privacy Policy".length(), spanTxt.length(), 0);
            view.setMovementMethod(LinkMovementMethod.getInstance());
            view.setText(spanTxt, BufferType.SPANNABLE);
        } 
    

    And in your XML, use android:textColorLink to add custom link color of your choice. Like this:

       <TextView
         android:id="@+id/textView1"
         android:layout_width="wrap_content"
         android:layout_height="wrap_content"
         android:text="TextView"
         android:textColorLink="#C36241" />  //#C36241 - Rust
    

    And this looks like this:

    enter image description here

    Hope it helps someone. :)

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