【问题标题】:How can I get clickable hyperlinks in AlertDialog from a string resource?如何从字符串资源中获取 AlertDialog 中的可点击超链接?
【发布时间】:2011-01-01 02:59:41
【问题描述】:

我想要完成的是在AlertDialog 显示的消息文本中添加可点击的超链接。虽然AlertDialog 实现很高兴地为任何超链接(在传递给Builder.setMessage 的字符串资源中使用<a href="..."> 定义)加下划线和着色,但提供的链接不会变成可点击的。

我目前使用的代码如下:

new AlertDialog.Builder(MainActivity.this).setTitle(
        R.string.Title_About).setMessage(
        getResources().getText(R.string.about))
        .setPositiveButton(android.R.string.ok, null)
        .setIcon(R.drawable.icon).show();

我想避免使用 WebView 来仅显示文本 sn-p。

【问题讨论】:

  • 嗨!你真的完成了声明的结果(“愉快地为任何超链接添加下划线和颜色”)吗?你传递的是什么字符串值?
  • 是的,关键是要让消息显示在字符串资源中,Resources.getText(...) 以 android.text.Spanned 形式返回,保留 HTML 格式。但是,一旦将其转换为字符串,魔法就会消失。

标签: android user-interface hyperlink custom-controls


【解决方案1】:

我不太喜欢当前最流行的答案,因为它显着改变了对话框中消息的格式。

这里有一个解决方案,可以在不改变文本样式的情况下链接您的对话框文本:

    // Linkify the message
    final SpannableString s = new SpannableString(msg); // msg should have url to enable clicking
    Linkify.addLinks(s, Linkify.ALL);

    final AlertDialog d = new AlertDialog.Builder(activity)
        .setPositiveButton(android.R.string.ok, null)
        .setIcon(R.drawable.icon)
        .setMessage( s )
        .create();

    d.show();

    // Make the textview clickable. Must be called after show()
    ((TextView)d.findViewById(android.R.id.message)).setMovementMethod(LinkMovementMethod.getInstance());

【讨论】:

  • 干杯,在onCreateDialogDialogFragment 内为我工作。只需在onStart 设置可点击代码,因为已调用show 来调用DialogFragment
  • 这似乎使整个 TextView 可点击,而不仅仅是链接......有什么办法吗?
  • 我同意这是一个更好的选择,因为最初的答案在视觉上搞乱了对话框。
  • findViewById 返回的视图应该用“instanceof TextView”检查,因为不能保证实现不会改变。
  • 正如在别处指出的那样,如果使用setMessage(R.string.something),则无需显式链接。在调用show() 之前也不需要create() AlertDialog 对象(它可以在Builder 上调用),并且由于show() 返回对话框对象,findViewById(android.R.id.message) 可以被链接。将其全部包装在一个 try-catch 中,以防消息视图不是 TextView,并且您有一个简洁的公式。
【解决方案2】:

如果您只在对话框中显示一些文本和 URL[s],则解决方案可能更简单

public static class MyOtherAlertDialog {

 public static AlertDialog create(Context context) {
  final TextView message = new TextView(context);
  // i.e.: R.string.dialog_message =>
            // "Test this dialog following the link to dtmilano.blogspot.com"
  final SpannableString s = 
               new SpannableString(context.getText(R.string.dialog_message));
  Linkify.addLinks(s, Linkify.WEB_URLS);
  message.setText(s);
  message.setMovementMethod(LinkMovementMethod.getInstance());

  return new AlertDialog.Builder(context)
   .setTitle(R.string.dialog_title)
   .setCancelable(true)
   .setIcon(android.R.drawable.ic_dialog_info)
   .setPositiveButton(R.string.dialog_action_dismiss, null)
   .setView(message)
   .create();
 }
}

如图所示 http://picasaweb.google.com/lh/photo/up29wTQeK_zuz-LLvre9wQ?feat=directlink

【讨论】:

  • 您可能想要创建一个布局文件并将其膨胀并用作视图。
  • 如何设置 textView 的样式以匹配默认使用的样式?
  • 然后,我收到错误 Calling startActivity() from outside of an Activity context requires the FLAG_ACTIVITY_NEW_TASK flag. Is this really what you want?
【解决方案3】:

这应该使<a href> 标签也被突出显示。请注意,我刚刚在 emmby 的代码中添加了几行代码。所以感谢他

final AlertDialog d = new AlertDialog.Builder(this)
 .setPositiveButton(android.R.string.ok, null)
 .setIcon(R.drawable.icon)
 .setMessage(Html.fromHtml("<a href=\"http://www.google.com\">Check this link out</a>"))
 .create();
d.show();
// Make the textview clickable. Must be called after show()   
    ((TextView)d.findViewById(android.R.id.message)).setMovementMethod(LinkMovementMethod.getInstance());

【讨论】:

  • 如果在strings.xml中使用html,则不需要使用Html.fromHtml。 setMessage(R.string.cool_link)&lt;string name="cool_link"&gt;&lt;a href="http://www.google.com"&gt;Check this link out&lt;/a&gt;&lt;/string&gt; 一起使用
  • 确实如此。当您结合这两种方法(Html.fromHtml 和 strings.xml 中的 HTML 标记)时,它不起作用。
  • 已经有一段时间了,fromHtml 已被弃用,现在怎么办?
  • setMovementMethod()是这里的重要部分,否则URL将无法点击。
  • 我在最后一行得到一个空指针异常,说 ((TextView)d.findViewById(android.R.id.message)) 为空。
【解决方案4】:

其实,如果你想简单地使用一个字符串而不处理所有的视图,最快的方法是找到消息文本视图并链接它:

d.setMessage("Insert your cool string with links and stuff here");
Linkify.addLinks((TextView) d.findViewById(android.R.id.message), Linkify.ALL);

【讨论】:

    【解决方案5】:

    JFTR,我在一段时间后想出的解决方案来了:

    View view = View.inflate(MainActivity.this, R.layout.about, null);
    TextView textView = (TextView) view.findViewById(R.id.message);
    textView.setMovementMethod(LinkMovementMethod.getInstance());
    textView.setText(R.string.Text_About);
    new AlertDialog.Builder(MainActivity.this).setTitle(
            R.string.Title_About).setView(view)
            .setPositiveButton(android.R.string.ok, null)
            .setIcon(R.drawable.icon).show();
    

    作为片段从 Android 源中借用的相应 about.xml 如下所示:

    <?xml version="1.0" encoding="utf-8"?>
    <ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
        android:id="@+id/scrollView" android:layout_width="fill_parent"
        android:layout_height="wrap_content" android:paddingTop="2dip"
        android:paddingBottom="12dip" android:paddingLeft="14dip"
        android:paddingRight="10dip">
        <TextView android:id="@+id/message" style="?android:attr/textAppearanceMedium"
            android:layout_width="fill_parent" android:layout_height="wrap_content"
            android:padding="5dip" android:linksClickable="true" />
    </ScrollView>
    

    重要的部分是将linksClickable设置为true和setMovementMethod(LinkMovementMethod.getInstance())。

    【讨论】:

    • 谢谢,这解决了我的问题。在我的情况下,setLinksClickable(true) 没有必要(我猜它已经是了),但 setMovementMethod(...) 发挥了重要作用。
    【解决方案6】:

    而不是...

    AlertDialog.Builder dialogBuilder = new AlertDialog.Builder(this);
    dialogBuilder.setTitle(R.string.my_title);
    dialogBuilder.setMessage(R.string.my_text);
    

    ...我现在使用:

    AlertDialog.Builder dialogBuilder = new AlertDialog.Builder(this);
    dialogBuilder.setTitle(R.string.my_title);
    TextView textView = new TextView(this);
    textView.setMovementMethod(LinkMovementMethod.getInstance());
    textView.setText(R.string.my_text);
    dialogBuilder.setView(textView);
    

    【讨论】:

    • 嘿,你的解决方案有效。你知道为什么点击链接时整个文本视图都会闪烁吗?
    • 它不像默认的那样滚动。
    【解决方案7】:

    最简单的方法:

    final AlertDialog dlg = new AlertDialog.Builder(this)
                    .setTitle(R.string.title)
                    .setMessage(R.string.message)
                    .setNeutralButton(R.string.close_button, null)
                    .create();
            dlg.show();
            // Important! android.R.id.message will be available ONLY AFTER show()
            ((TextView)dlg.findViewById(android.R.id.message)).setMovementMethod(LinkMovementMethod.getInstance());
    

    【讨论】:

      【解决方案8】:

      如果给定的字符串包含,上述所有答案都不会删除 html 标签等,我试图删除所有标签,这对我来说很好

      AlertDialog.Builder builder = new AlertDialog.Builder(ctx);
              builder.setTitle("Title");
      
              LayoutInflater inflater = (LayoutInflater) ctx.getSystemService(LAYOUT_INFLATER_SERVICE);
              View layout = inflater.inflate(R.layout.custom_dialog, null);
      
              TextView text = (TextView) layout.findViewById(R.id.text);
              text.setMovementMethod(LinkMovementMethod.getInstance());
              text.setText(Html.fromHtml("<b>Hello World</b> This is a test of the URL <a href=http://www.example.com> Example</a><p><b>This text is bold</b></p><p><em>This text is emphasized</em></p><p><code>This is computer output</code></p><p>This is<sub> subscript</sub> and <sup>superscript</sup></p>";));
              builder.setView(layout);
      AlertDialog alert = builder.show();
      

      custom_dialog 就像;

      <?xml version="1.0" encoding="utf-8"?>
      <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
                    android:id="@+id/layout_root"
                    android:orientation="horizontal"
                    android:layout_width="fill_parent"
                    android:layout_height="fill_parent"
                    android:padding="10dp"
                    >
      
          <TextView android:id="@+id/text"
                    android:layout_width="wrap_content"
                    android:layout_height="fill_parent"
                    android:textColor="#FFF"
                    />
      </LinearLayout>
      

      上述代码将删除所有 html 标记,并在指定的 html 格式文本中将示例显示为可点击的 URL。

      【讨论】:

        【解决方案9】:

        我对当前的答案并不满意。当您想要带有 AlertDialog 的 href 样式的可点击超链接时,有两点很重要:

        1. 将内容设置为 View 而不是 setMessage(…),因为只有 View 才允许可点击的 HTML 内容
        2. 设置正确的移动方式(setMovementMethod(…))

        这是一个最小的工作示例:

        strings.xml

        <string name="dialogContent">
            Cool Links:\n
            <a href="http://stackoverflow.com">Stackoverflow</a>\n
            <a href="http://android.stackexchange.com">Android Enthusiasts</a>\n
        </string>
        

        MyActivity.java

        …
        public void showCoolLinks(View view) {
           final TextView textView = new TextView(this);
           textView.setText(R.string.dialogContent);
           textView.setMovementMethod(LinkMovementMethod.getInstance()); // this is important to make the links clickable
           final AlertDialog alertDialog = new AlertDialog.Builder(this)
               .setPositiveButton("OK", null)
               .setView(textView)
               .create();
           alertDialog.show()
        }
        …
        

        【讨论】:

        • 这很好用,但警报中的文本从最左边开始,没有任何空格。您可以使用textView.setPadding() 轻松调整它
        【解决方案10】:

        我检查了很多问题和答案,但都不起作用。我自己做的。这是 MainActivity.java 上的代码 sn-p。

        private void skipToSplashActivity()
        {
        
            final TextView textView = new TextView(this);
            final SpannableString str = new SpannableString(this.getText(R.string.dialog_message));
        
            textView.setText(str);
            textView.setMovementMethod(LinkMovementMethod.getInstance());
        
            ....
        }
        

        将此标签放在 res\values\String.xml 上

        <string name="dialog_message"><a href="http://www.nhk.or.jp/privacy/english/">NHK Policy on Protection of Personal Information</a></string>
        

        【讨论】:

          【解决方案11】:

          如果您使用的是DialogFragment,此解决方案应该会有所帮助。

          public class MyDialogFragment extends DialogFragment {
              @Override
              public Dialog onCreateDialog(Bundle savedInstanceState) {
          
                  // dialog_text contains "This is a http://test.org/"
                  String msg = getResources().getString(R.string.dialog_text);
                  SpannableString spanMsg = new SpannableString(msg);
                  Linkify.addLinks(spanMsg, Linkify.ALL);
          
                  AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());
                  builder.setTitle(R.string.dialog_title)
                      .setMessage(spanMsg)
                      .setPositiveButton(R.string.ok, null);
                  return builder.create();
              }
          
              @Override
              public void onStart() {
                  super.onStart();
          
                  // Make the dialog's TextView clickable
                  ((TextView)this.getDialog().findViewById(android.R.id.message))
                          .setMovementMethod(LinkMovementMethod.getInstance());
              }
          }
          

          【讨论】:

          • 如果将 SpannableString 设置为对话框的消息,则链接会突出显示,但不可点击。
          • @bk138 onStart() 中对 .setMovementMethod() 的调用是使链接可点击的原因。
          【解决方案12】:

          对我来说,创建隐私政策对话框的最佳解决方案是:

              private void showPrivacyDialog() {
              if (!PreferenceManager.getDefaultSharedPreferences(getApplicationContext()).getBoolean(PRIVACY_DIALOG_SHOWN, false)) {
          
                  String privacy_pol = "<a href='https://sites.google.com/view/aiqprivacypolicy/home'> Privacy Policy </a>";
                  String toc = "<a href='https://sites.google.com/view/aiqprivacypolicy/home'> T&C </a>";
                  AlertDialog dialog = new AlertDialog.Builder(this)
                          .setMessage(Html.fromHtml("By using this application, you agree to " + privacy_pol + " and " + toc + " of this application."))
                          .setPositiveButton("ACCEPT", new DialogInterface.OnClickListener() {
                              public void onClick(DialogInterface dialog, int which) {
                                  PreferenceManager.getDefaultSharedPreferences(getApplicationContext()).edit().putBoolean(PRIVACY_DIALOG_SHOWN, true).apply();
                              }
                          })
                          .setNegativeButton("DECLINE", null)
                          .setCancelable(false)
                          .create();
          
                  dialog.show();
                  TextView textView = dialog.findViewById(android.R.id.message);
                  textView.setLinksClickable(true);
                  textView.setClickable(true);
                  textView.setMovementMethod(LinkMovementMethod.getInstance());
              }
          }
          

          检查工作示例:app link

          【讨论】:

            【解决方案13】:

            我结合了上面讨论的一些选项来提出适合我的功能。将结果传递给对话框生成器的 SetView() 方法。

            public ScrollView LinkifyText(String message) 
            {
                ScrollView svMessage = new ScrollView(this); 
                TextView tvMessage = new TextView(this);
            
                SpannableString spanText = new SpannableString(message);
            
                Linkify.addLinks(spanText, Linkify.ALL);
                tvMessage.setText(spanText);
                tvMessage.setMovementMethod(LinkMovementMethod.getInstance());
            
                svMessage.setPadding(14, 2, 10, 12);
                svMessage.addView(tvMessage);
            
                return svMessage;
            }
            

            【讨论】:

              【解决方案14】:

              我通过在 XML 资源中指定警报框并加载它来做到这一点。例如,请参阅在 ChandlerQE.java 末尾附近实例化的 about.xml(请参阅 ABOUT_URL id)。 java代码中的相关部分:

              LayoutInflater inflater = 
                  (LayoutInflater)getSystemService(Context.LAYOUT_INFLATER_SERVICE);
              View view = (View) inflater.inflate(R.layout.about, null);
              
              new AlertDialog.Builder(ChandlerQE.this)
              .setTitle(R.string.about)
              .setView(view)
              

              【讨论】:

              • 链接失效了,你能修复它吗?
              【解决方案15】:

              这是我的解决方案。它创建一个不涉及 html 标记且不可见任何 URL 的普通链接。它还保持设计完好无损。

              SpannableString s = new SpannableString("This is my link.");
              s.setSpan(new URLSpan("http://www.google.com"), 11, 15, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
              
              AlertDialog.Builder builder;
              if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
                  builder = new AlertDialog.Builder(this, android.R.style.Theme_Material_Dialog_Alert);
              } else {
                  builder = new AlertDialog.Builder(this);
              }
              
              final AlertDialog d = builder
                      .setPositiveButton("CLOSE", new DialogInterface.OnClickListener() {
                          public void onClick(DialogInterface dialog, int which) {
                              // Do nothing, just close
                          }
                      })
                      .setNegativeButton("SHARE", new DialogInterface.OnClickListener() {
                          public void onClick(DialogInterface dialog, int which) {
                              // Share the app
                              share("Subject", "Text");
                          }
                      })
                      .setIcon(R.drawable.photo_profile)
                      .setMessage(s)
                      .setTitle(R.string.about_title)
                      .create();
              
              d.show();
              
              ((TextView)d.findViewById(android.R.id.message)).setMovementMethod(LinkMovementMethod.getInstance());
              

              【讨论】:

              • 谢谢,只是添加 setSpan(URL, startPoint, endPoint, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE)。这里 startPoint 和 endPoint 是高亮显示的单词
              【解决方案16】:

              简单的 Kotlin 实现

              字符串资源:

              <string name="foo"><a href="https://www.google.com/">some link</a></string>
              

              代码:

              AlertDialog.Builder(context)
                      .setMessage(R.string.foo)
                      .show()
                      .apply {
                          findViewById<TextView>(android.R.id.message)
                          ?.movementMethod = LinkMovementMethod.getInstance()
                      }
              

              【讨论】:

                【解决方案17】:

                最简单最短的方法是这样的

                Android link in dialog

                ((TextView) new AlertDialog.Builder(this)
                .setTitle("Info")
                .setIcon(android.R.drawable.ic_dialog_info)
                .setMessage(Html.fromHtml("<p>Sample text, <a href=\"http://google.nl\">hyperlink</a>.</p>"))
                .show()
                // Need to be called after show(), in order to generate hyperlinks
                .findViewById(android.R.id.message))
                .setMovementMethod(LinkMovementMethod.getInstance());
                

                【讨论】:

                • 你能告诉我如何在 Kotlin 中做到这一点吗?
                • 对不起。我不知道 Kotlin
                【解决方案18】:

                这是我使用的简单方法

                strings.xml 中的字符串

                <?xml version="1.0" encoding="utf-8"?>
                <resources xmlns:tools="http://schemas.android.com/tools">
                    <string name="credits_title">Credits</string>
                    <string name="confirm">OK</string>
                    <string name="credits">All rights reserved.
                         <a href="https://google.com">Source</a>
                    </string>
                </resources>
                

                dimens.xml 中的维度

                <?xml version="1.0" encoding="utf-8"?>
                <resources xmlns:tools="http://schemas.android.com/tools">
                    <dimen name="margin_8dp">8dp</dimen>
                    <dimen name="margin_32dp">32dp</dimen>
                </resources>
                

                助手对话框类

                public class MessageHelper {
                
                    public static void showCreditsDialog(Context context) {
                
                        AlertDialog alertDialog = new AlertDialog.Builder(context).create();
                        alertDialog.setTitle(R.string.credits_title);
                        TextView textView = new TextView(context);
                        int padding = (int) context.getResources().getDimension(R.dimen.margin_32dp);
                        int topPadding = (int) context.getResources().getDimension(R.dimen.margin_8dp);
                        textView.setPadding(padding, topPadding, padding, 0);
                        textView.setMovementMethod(LinkMovementMethod.getInstance());
                        textView.setText(R.string.credits);
                        alertDialog.setView(textView);
                
                        alertDialog.setButton(AlertDialog.BUTTON_NEUTRAL, context.getResources().getString(R.string.confirm),
                                new DialogInterface.OnClickListener() {
                                    public void onClick(DialogInterface dialog, int which) {
                                        dialog.dismiss();
                                    }
                                });
                        alertDialog.show();
                    }
                }
                

                如何使用

                MessageHelper.showCreditsDialog(this); // this is the context
                

                预览

                【讨论】:

                  【解决方案19】:

                  AlertDialog 中的可点击超链接

                   /*Dialog Agreement*/
                      private fun agreed() {
                          if (agreed != "yes") {
                              val inflater: LayoutInflater = this.layoutInflater
                              val dialogView: View = inflater.inflate(R.layout.dialog_agreed, null)
                              val btnAccept: TextView = dialogView.findViewById(R.id.btn_accept)
                              val btnDecline: TextView = dialogView.findViewById(R.id.btn_decline)
                              val txtMessage: TextView = dialogView.findViewById(R.id.txt_message)
                              btnAccept.setOnClickListener {
                                  //Saving data to preference manager
                                  val sharedPref = getSharedPreferences("Janta24", Context.MODE_PRIVATE)
                                  val editor = sharedPref.edit()
                                  editor.putString("agreed", "yes")
                                  editor.apply()
                                  alertDialog.dismiss()
                              }
                              btnDecline.setOnClickListener {
                                  finish()
                              }
                              txtMessage.text = Html.fromHtml(
                                  "We have revised our<a href=\"http://app.janta24.in/term.html\">Terms of Use</a> & " +
                                          "<a href=\"http://app.janta24.in/privacy.html\">Privacy Policy</a> " +
                                          "By accepting, you agreed to our updated terms and policies. Please take few minutes to read and understand them."
                              )
                              txtMessage.movementMethod = LinkMovementMethod.getInstance()
                              val dialogBuilder: AlertDialog.Builder = AlertDialog.Builder(this)
                              dialogBuilder.setOnDismissListener { }
                              dialogBuilder.setView(dialogView)
                              dialogBuilder.setCancelable(false)
                              alertDialog = dialogBuilder.create()
                              alertDialog.show()
                          }
                      }
                  

                  【讨论】:

                    猜你喜欢
                    • 2012-03-01
                    • 1970-01-01
                    • 2015-03-13
                    • 2021-10-08
                    • 2016-06-01
                    • 2021-03-04
                    • 1970-01-01
                    • 1970-01-01
                    • 2019-10-13
                    相关资源
                    最近更新 更多