143

What I am trying to accomplish is to have clickable hyperlinks in the message text displayed by an AlertDialog. While the AlertDialog implementation happily underlines and colors any hyperlinks (defined using <a href="..."> in the string resource passed to Builder.setMessage) supplied the links do not become clickable.

The code I am currently using looks like this:

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

I'd like to avoid using a WebView to just display a text snippet.

Willi Mentzel
  • 27,862
  • 20
  • 113
  • 121
Thilo-Alexander Ginkel
  • 6,898
  • 10
  • 45
  • 58
  • Hi! Do you really accomplish declared results ("happily underlines and colors any hyperlinks")? What string value are you passing? – Maksym Gontar Jan 04 '10 at 07:08
  • 1
    Yes, the key is to have the message to be displayed in a string resource, which Resources.getText(...) returns as a android.text.Spanned preserving the HTML formatting. As soon as you convert it to a String, though, the magic vanishes. – Thilo-Alexander Ginkel Jan 04 '10 at 13:01

19 Answers19

216

I didn't really like the currently most popular answer because it significantly changes the formatting of the message in the dialog.

Here's a solution that will linkify your dialog text without otherwise changing the text styling:

    // 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());
CopsOnRoad
  • 237,138
  • 77
  • 654
  • 440
emmby
  • 99,783
  • 65
  • 191
  • 249
  • This is the solution that I chose, thanks. One problem however is that it doesn't work for normal html links of the form resume. Maybe the one-arg Linkify.addLinks doesn't know how to do that yet? Does anyone know the regex pattern needed to make that work with the fancier versions of addLinks? It's odd because it works fine with my similar mailto link. – Melinda Green Jan 25 '11 at 21:02
  • 5
    Cheers, Worked for me from within `onCreateDialog` of a `DialogFragment`. Just had to set clickable code at `onStart` given that `show` had been called to invoke the DialogFragment – PJL Jun 10 '11 at 16:33
  • 6
    This seems to make the entire TextView clickable as opposed to just the links... Any way around this? – Kavi Jan 26 '12 at 22:44
  • 1
    I agree this is a far better option since the original answer is messing up the dialog visually. – hcpl Mar 23 '12 at 21:07
  • Hey this works fine for me, but are we able to change the text link color to something different, and remove the underline? – aimango Mar 29 '12 at 17:59
  • Never mind, found it here: http://stackoverflow.com/questions/4542210/change-color-of-hyperlink-in-alertdialog – aimango Mar 29 '12 at 18:48
  • Excellent answer. I had to throw in a `((TextView)d.findViewById(android.R.id.message)).setClickable(true);` before it worked. – Peter Ajtai Apr 05 '12 at 22:45
  • WOW man, I was suffered from this styling issue for a long time. You saved my app. Thank you. – tasomaniac Feb 21 '13 at 12:11
  • 1
    View returned by findViewById should be checked with "instanceof TextView", because there is no guarantee that implementation will not change. – Denis Gladkiy Mar 05 '14 at 04:59
  • 6
    As pointed out elsewhere, if using `setMessage(R.string.something)`, it is not necessary to explicitly linkify. It's also not necessary to `create()` the AlertDialog object prior to calling `show()` (it can be called on the Builder), and since `show()` returns the dialog object, the `findViewById(android.R.id.message)` can be chained. Wrap it all in a try-catch just in case the message view is not a TextView, and you have a concise formulation. – Pierre-Luc Paour Apr 24 '14 at 15:15
  • this looses any formated text when using this approach – Jono Apr 13 '15 at 09:04
  • Hello, When click on the Hyper link, it doesn't open in the browser.Just display "Open with" but not showing any other option.Is there any way to open link directly in browser.? Thanks. – VP4Android Jun 15 '18 at 17:42
  • @emmby Is there any chance to change the color of the link? – MashukKhan Apr 16 '21 at 05:30
131

If you are only showing some text and URL[s] in your dialog perhaps the solution is simpler

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

As shown here http://picasaweb.google.com/lh/photo/up29wTQeK_zuz-LLvre9wQ?feat=directlink

Alert dialog with clickable links

gideon
  • 19,329
  • 11
  • 72
  • 113
Diego Torres Milano
  • 65,697
  • 9
  • 111
  • 134
55

This should make <a href> tags to get highlighted as well. Please note that i have just added a few lines to emmby's code. so credit to him

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());
DeRagan
  • 22,827
  • 6
  • 41
  • 50
  • 10
    If you use html in strings.xml, you don't need to use Html.fromHtml. `setMessage(R.string.cool_link)` works with `Check this link out` – idbrii Jun 17 '11 at 22:30
  • 2
    That is true. When you combine both methods (Html.fromHtml and HTML tag in strings.xml) it does notwork. – JerabekJakub Jul 18 '14 at 07:50
  • Its been a while and fromHtml is deprecated, now what? – Menasheh Jul 21 '16 at 04:36
  • You can still use fromHtml: https://developer.android.com/reference/android/text/Html.html#fromHtml(java.lang.String, int) Simply use ```Html.fromHtml("string with links", Html.FROM_HTML_MODE_LEGACY)``` – BVB Sep 15 '16 at 17:25
  • 2
    `setMovementMethod()` is the important part here, otherwise the URL will not be clickable. – scai Dec 10 '16 at 16:38
  • 1
    I get a null pointer exception at the last line saying that `((TextView)d.findViewById(android.R.id.message))` is null. – Donald Duck Aug 18 '21 at 09:26
13

Actually, if you want to simply use a string without dealing with all the views, the fastest way is to find message textview and linkify it:

d.setMessage("Insert your cool string with links and stuff here");
Linkify.addLinks((TextView) d.findViewById(android.R.id.message), Linkify.ALL);
vinc3m1
  • 4,075
  • 1
  • 26
  • 23
12

JFTR, here comes the solution which I figured out after some time:

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

The corresponding about.xml borrowed as a fragment from the Android sources looks like this:

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

The important parts are setting linksClickable to true and setMovementMethod(LinkMovementMethod.getInstance()).

Thilo-Alexander Ginkel
  • 6,898
  • 10
  • 45
  • 58
  • Thank you, this solved the problem for me. In my case, it wasn't necessary to `setLinksClickable(true)` (I guess it already was), but `setMovementMethod(...)` made all the difference. – LarsH Jun 15 '16 at 23:03
10

Instead of ...

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

... I now use:

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);
neu242
  • 15,796
  • 20
  • 79
  • 114
7

Simplest way:

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());
Gabriele
  • 177
  • 1
  • 3
6

All the above answer will not remove html tag like , etc if the given string contains, I tried to remove all the tags, and this is work fine for me

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

and the custom_dialog would be like;

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

The above code will remove all the html tag and shows Example as Click able URL all others in the specified html formatting text.

Lakshmanan
  • 1,671
  • 2
  • 26
  • 42
5

I was not really satisfied with the current answers. There are two things that are important when you want clickable hyperlinks in href style withing an AlertDialog:

  1. Set the content as View and not with setMessage(…), as only Views allow clickable HTML content
  2. Set the correct movement method (setMovementMethod(…))

Here is a working minimal example:

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()
}
…
Elletlar
  • 3,136
  • 7
  • 32
  • 38
Flow
  • 23,572
  • 15
  • 99
  • 156
  • This works perfectly but the text in the Alert is starting from the very left, without any blank space. You can easily adjust that with `textView.setPadding()` – Michele Sep 17 '20 at 09:07
5

For me the best solution to create privacy policy dialog is :

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

check the working example : app link

Minion
  • 964
  • 14
  • 16
3

I've checked many questions and answers, but it doesn't work. I did it myself. This is the code snippet on MainActivity.java.

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

    ....
}

Put this tag on 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>
Hiroto
  • 133
  • 2
  • 13
3

If you are using a DialogFragment, this solution should help.

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());
    }
}
tronman
  • 9,862
  • 10
  • 46
  • 61
  • If you set the SpannableString as the dialog's message, the link is highlighted, but not clickable. – bk138 Jan 14 '17 at 17:35
  • @bk138 The call to .setMovementMethod() in onStart() is what makes the link clickable. – tronman Jan 15 '17 at 20:50
2

I combined some of the options discussed above to come up with this function that works for me. pass the result to dialog builder's SetView() method.

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;
}
Alex
  • 9,250
  • 11
  • 70
  • 81
2

Easy Kotlin implementation

String resource:

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

Code:

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

I do this by specifying the alert box in an XML resource and loading that. See for example the about.xml (see the ABOUT_URL id) that gets instantiated near the end of ChandlerQE.java. The relevant parts from the java code:

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)
Maksym Gontar
  • 22,765
  • 10
  • 78
  • 114
Heikki Toivonen
  • 30,964
  • 11
  • 42
  • 44
1

This is my solution. It creates a normal link without html tags involved and without any URL visible. It also keeps the design intact.

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());
John T
  • 814
  • 10
  • 17
  • 1
    Thanks, Just to add setSpan(URL, startPoint, endPoint, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE). Here startPoint and endPoint are words which will be highlighted for clicking – Manish Dec 18 '19 at 15:44
0

The easiest and shortest way is like this

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

This is the simple way I use

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

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

Helper Dialog class

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

How to use

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

Preview

enter image description here

Zain
  • 37,492
  • 7
  • 60
  • 84
0

Clickable hyperlinks in 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()
        }
    }
Aftab Alam
  • 1,969
  • 17
  • 17