¿Cómo puedo obtener hipervínculos clicables en AlertDialog desde un recurso de cadena?

134

Lo que estoy tratando de lograr es tener hipervínculos en los que se pueda hacer clic en el texto del mensaje que se muestra con un AlertDialog. Si bien la AlertDialogimplementación subraya y colorea felizmente los hipervínculos (definidos mediante <a href="...">el recurso de cadena pasado Builder.setMessage) suministrados, los enlaces no se pueden hacer clic.

El código que estoy usando actualmente se ve así:

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

Me gustaría evitar usar un WebViewsolo para mostrar un fragmento de texto.

Thilo-Alexander Ginkel
fuente
¡Hola! ¿Realmente logra resultados declarados ("subraya y colorea felizmente cualquier hipervínculo")? ¿Qué valor de cadena estás pasando?
Maksym Gontar
1
Sí, la clave es que el mensaje se muestre en un recurso de cadena, que Resources.getText (...) devuelve como android.text.Spanned conservando el formato HTML. Sin embargo, tan pronto como lo conviertes en una Cadena, la magia desaparece.
Thilo-Alexander Ginkel

Respuestas:

128

Si solo muestra algo de texto y URL [s] en su diálogo, tal vez la solución sea más simple

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

Como se muestra aquí http://picasaweb.google.com/lh/photo/up29wTQeK_zuz-LLvre9wQ?feat=directlink

Diálogo de alerta con enlaces en los que se puede hacer clic

Diego Torres Milano
fuente
1
probablemente desee crear un archivo de diseño e inflarlo y usarlo como vista.
Jeffrey Blattman
55
¿Cómo establecería el estilo de textView para que coincida con el utilizado por defecto?
Desarrollador de Android
3
Entonces, recibo un errorCalling startActivity() from outside of an Activity context requires the FLAG_ACTIVITY_NEW_TASK flag. Is this really what you want?
ViliusK
207

Realmente no me gustó la respuesta más popular actualmente porque cambia significativamente el formato del mensaje en el cuadro de diálogo.

Aquí hay una solución que vinculará el texto del diálogo sin cambiar el estilo del texto:

    // 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());
emmby
fuente
55
Saludos, trabajó para mí desde dentro onCreateDialogde a DialogFragment. Sólo tenía que programar un nuevo código se puede hacer clic en onStartTeniendo en cuenta que showhabía sido llamado para invocar el DialogFragment
PJL
55
Esto parece hacer que se pueda hacer clic en todo el TextView en lugar de solo los enlaces ... ¿Alguna forma de evitar esto?
Kavi
1
Estoy de acuerdo en que esta es una opción mucho mejor ya que la respuesta original es desordenar visualmente el diálogo.
hcpl
1
La vista devuelta por findViewById debe verificarse con "instanceof TextView", porque no hay garantía de que la implementación no cambie.
Denis Gladkiy
66
Como se señaló en otra parte, si se usa setMessage(R.string.something), no es necesario vincular explícitamente. Tampoco es necesario para create()el objeto AlertDialog antes de llamar show()(se puede invocar en el generador ), y dado que show()devuelve el objeto de diálogo, findViewById(android.R.id.message)se puede encadenar. Envuélvelo todo en un try-catch en caso de que la vista del mensaje no sea TextView y tengas una formulación concisa.
Pierre-Luc Paour
50

Esto debería hacer que las <a href>etiquetas se resalten también. Tenga en cuenta que acabo de agregar algunas líneas al código de emmby. así que acéptalo

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
fuente
10
Si usa html en strings.xml, no necesita usar Html.fromHtml. setMessage(R.string.cool_link)funciona con<string name="cool_link"><a href="http://www.google.com">Check this link out</a></string>
idbrii
2
Eso es verdad. Cuando combina ambos métodos (Html.fromHtml y etiqueta HTML en strings.xml) no funciona.
JerabekJakub
Ha pasado un tiempo y fromHtml está en desuso, ¿y ahora qué?
Menasheh
Todavía puede usar fromHtml: developer.android.com/reference/android/text/… , int) Simplemente useHtml.fromHtml("string with links", Html.FROM_HTML_MODE_LEGACY)
BVB
2
setMovementMethod()es la parte importante aquí, de lo contrario no se podrá hacer clic en la URL.
scai
13

En realidad, si desea simplemente usar una cadena sin ocuparse de todas las vistas, la forma más rápida es encontrar la vista de texto del mensaje y vincularlo:

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

JFTR, aquí viene la solución que descubrí después de un tiempo:

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

El about.xml correspondiente prestado como un fragmento de las fuentes de Android se ve así:

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

Las partes importantes son establecer linksClickable a true y setMovementMethod (LinkMovementMethod.getInstance ()).

Thilo-Alexander Ginkel
fuente
Gracias, esto resolvió el problema para mí. En mi caso, no fue necesario setLinksClickable(true)(supongo que ya lo era), pero setMovementMethod(...)marcó la diferencia.
LarsH
10

En vez de ...

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

... ahora uso:

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
fuente
Oye, tu solución funciona. ¿sabes por qué parpadea toda la vista de texto al hacer clic en el enlace?
aimango
No se desplaza como el predeterminado.
Meow Cat 2012
7

La forma más simple:

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

Toda la respuesta anterior no eliminará la etiqueta html como, etc. si la cadena dada contiene, intenté eliminar todas las etiquetas, y esto funciona bien para mí

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

y el custom_dialog sería como;

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

El código anterior eliminará todas las etiquetas html y muestra el Ejemplo como URL capaz de hacer clic en todas las demás en el texto de formato html especificado.

Lakshmanan
fuente
5

No estaba realmente satisfecho con las respuestas actuales. Hay dos cosas que son importantes cuando desea hipervínculos clicables en estilo href dentro de un AlertDialog:

  1. Establecer el contenido como Ver y no con setMessage(…) , ya que solo las Vistas permiten contenido HTML en el que se puede hacer clic
  2. Establecer el método de movimiento correcto ( setMovementMethod(…))

Aquí hay un ejemplo mínimo de trabajo:

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()
}
Fluir
fuente
3

He revisado muchas preguntas y respuestas, pero no funciona. Lo hice yo mismo. Este es el fragmento de código en 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());

    ....
}

Pon esta etiqueta en 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
fuente
2

Combiné algunas de las opciones discutidas anteriormente para crear esta función que funciona para mí. pasar el resultado al método SetView () del generador de diálogo.

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

Si está utilizando a DialogFragment, esta solución debería ayudar.

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
fuente
Si configura la SpannableString como mensaje del cuadro de diálogo, el enlace se resalta, pero no se puede hacer clic en él.
bk138
@ bk138 La llamada a .setMovementMethod () en onStart () es lo que hace que se pueda hacer clic en el enlace.
tronman
2

Para mí, la mejor solución para crear un diálogo de política de privacidad es:

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

verifique el ejemplo de trabajo: enlace de la aplicación

Esbirro
fuente
1

Hago esto especificando el cuadro de alerta en un recurso XML y cargando eso. Consulte, por ejemplo, el about.xml (consulte el ID ABOUT_URL) que se instancia cerca del final de ChandlerQE.java . Las partes relevantes del código de 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)
Heikki Toivonen
fuente
el enlace está muerto, ¿puedes arreglarlo?
Bijoy Thangaraj
1

Esta es mi solución Crea un enlace normal sin etiquetas html involucradas y sin ninguna URL visible. También mantiene el diseño intacto.

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
fuente
1
Gracias, solo para agregar setSpan (URL, startPoint, endPoint, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE). Aquí startPoint y endPoint son palabras que se resaltarán al hacer clic
Manish
0

La forma más fácil y más corta es así

Enlace de Android en diálogo

((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());
Javier Castellanos Cruz
fuente
¿Me puede decir cómo hacer esto en Kotlin?
Thomas Williams
Lo siento. No sé Kotlin
Javier Castellanos Cruz