java Android 上 TextView 中的多个可点击链接

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/28720117/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-11-02 14:04:21  来源:igfitidea点击:

Multiple Clickable links in TextView on Android

javaandroidandroid-layouttextview

提问by AndroidEnthusiast

I'm trying to add multiple links in a textview similar to what Google & Flipboard has done below with their Terms and conditionsAND Privacy Policyshown in the screen shot below:

我想添加多个链接以类似于谷歌与Flipboard的下面已经与他们做一个TextView条款和条件隐私政策的屏幕截图如下图所示:

So far I've stumbled on using this approach

到目前为止,我偶然发现了使用这种方法

textView.setText(Html.fromHtml(myHtml); textView.setMovementMethod(LinkMovementMethod.getInstance());

textView.setText(Html.fromHtml(myHtml); textView.setMovementMethod(LinkMovementMethod.getInstance());

where myHtml is a href.

其中 myHtml 是一个 href。

But it doesn't give me control I need e.g to launch a fragment etc.

但这并没有让我控制我需要的控制,例如启动片段等。

Any idea how they achieve this in the two examples below?

知道他们如何在下面的两个示例中实现这一目标吗?

Flipboard terms and conditions view

Flipboard 条款和条件视图

Google terms and conditions view

Google 条款和条件视图

采纳答案by harrane

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

您可以使用Linkifyandroid.text.Spannablejava.util.regex.Patternjava.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:

然后您可以使用该方案来启动一个活动,例如通过在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.

如果您想执行自定义操作,您可以将意图过滤器设置为您当前的活动,该活动将具有 singleTop 启动模式。

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

这将导致onNewIntent在可以进行自定义操作的地方被触发:

@Override
protected void onNewIntent(final Intent intent) {
 ...
  if (intent.getScheme().equals(..)) {
    ..
  }
}

回答by Tushar Gogna

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

我想我分享这个有点晚了,但我使用SpannableStringBuilder实现了同样的目标

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

只需初始化TextView要添加 2 个或更多侦听器的对象,然后将其传递给我创建的以下方法:

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:textColorLinkto add custom link color of your choice. Like this:

在您的 XML 中,用于android:textColorLink添加您选择的自定义链接颜色。像这样:

   <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. :)

希望它可以帮助某人。:)

回答by Ahmad Baraka

Here's my solution:

这是我的解决方案:

First we need to have clickable links in our TextView:

首先,我们需要在 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());
    
  1. 这是我在 xml 布局中的 TextView,不添加任何链接处理参数。

    <TextView
            android:id="@+id/sign_up_privacy"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="@string/terms_and_privacy"/>
    
  2. 在字符串文件中,我添加了带有 html 标签的资源文本

    <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. 在 onCreateView 中将 LinkMovementMethod 设置为 TextView

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

Now the TextView links are clickable.

现在 TextView 链接是可点击的。

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);
            }
        }
    
  1. 在我的清单文件中,我为“条款”和“隐私”以及单实例启动模式添加了意图过滤器

    <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. 在 MyActivity 中,覆盖 onNewIntent 以捕获隐私和条款意图

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

回答by PH88

With Textoo, this can be achieved like:

使用Textoo,这可以像这样实现:

res/values/strings.xml:

res/values/strings.xml:

<resources>
     <string name="str_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>
</resources>

res/layout/myActivity.xml:

res/layout/myActivity.xml:

<TextView
    android:id="@+id/view_terms_and_privacy"
    android:text="@string/str_terms_and_privacy"
    />

java/myPackage/MyActivity.java:

java/myPackage/MyActivity.java:

public class MyActivity extends Activity {
    ...
    protected void onCreate(Bundle savedInstanceState) {
        ...
        TextView termsAndPrivacy = Textoo
            .config((TextView) findViewById(R.id.view_terms_and_privacy))
            .addLinksHandler(new LinksHandler() {
                @Override
                public boolean onClick(View view, String url) {
                    if ("terms:".equals(url)) {
                        // Handle terms click
                        return true;  // event handled
                    } else if ("privacy:".equals(url)) {
                        // Handle privacy click
                        return true;  // event handled
                    } else {
                        return false;  // event not handled.  continue default processing i.e. launch web browser and display the link
                    }
                }
            })
            .apply();
        ...
    }
    ...
}

This approach have the advantages that:

这种方法具有以下优点:

  • Keep text externalized as string resource. Make it easier to localize your app.
  • Can handle the click event directly using LinksHandlerand no need to define additional intent filter
  • Simpler and more readable code
  • 将文本外部化为字符串资源。更轻松地本地化您的应用程序。
  • 可以直接使用处理点击事件LinksHandler,无需定义额外的意图过滤器
  • 更简单、更易读的代码

回答by techtinkerer

This is working for me :

这对我有用:

in xml :

在 xml 中:

<TextView
    android:id="@+id/tv_by_continuing_str"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:layout_marginTop="8dp"
    android:layout_marginLeft="8dp"
    android:layout_marginRight="8dp"
    android:textSize="15sp"
    tools:text="Test msg 1 2, 3"
    android:textColor="@color/translucent_less_white3"
    android:textColorLink="@color/white"
    android:gravity="center|bottom"
    android:layout_above="@+id/btn_privacy_continue" />

In strings.xml

在strings.xml中

< string name="by_continuing_str2">< ! [ CDATA[By continuing to use this app, you agree to our <a href="https://go.test.com" style="color:gray"/> Privacy Statement </a> and <a href="https://go.test.com" style="color:gray"/>Services Agreement.]]>< / string>

in the activity :

在活动中:

TextView tv_by_continuing = (TextView) findViewById(R.id.tv_by_continuing);
tv_by_continuing.setText(Html.fromHtml(getString(R.string.by_continuing_str2)));
tv_by_continuing.setMovementMethod(LinkMovementMethod.getInstance());

回答by Salman khan

The best way to do this is with string file

最好的方法是使用字符串文件

In string.xml

在 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

在 onCreateView 调用下面的方法

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

回答by Deutro

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?

还是必须只使用一个标签?