Android — стиль AlertDialog

У меня есть диалоговое окно предупреждения в приложении, как показано ниже.

введите здесь описание изображения

Я хочу, чтобы заголовок и строка, отделяющая заголовок от тела сообщения, были оранжевого цвета. Как я могу это сделать? Я пробовал использовать собственный стиль, как показано ниже. Но это не сработало.

<style name="AboutDialog" parent="@android:style/Theme.Dialog">
  <item name="android:textColor">#E5492A</item>
</style>

мой код диалогового окна предупреждения:

AlertDialog.Builder alertDialog = new AlertDialog.Builder( new ContextThemeWrapper(MainActivity.context, R.style.AboutDialog));
alertDialog.setTitle("Sample");
        alertDialog.setMessage(R.string.rate_dialog_text);
        alertDialog.setPositiveButton(R.string.rate_now_text,
                new DialogInterface.OnClickListener() {
                    public void onClick(DialogInterface dialog, int which) {
                        MainActivity.context.startActivity(new Intent(
                                Intent.ACTION_VIEW, Uri
                                        .parse("market://details?id="
                                                + MainActivity.APP_PNAME)));
                        if (editor != null) {
                            editor.putBoolean("dontshowagain", true);
                            editor.commit();
                        }
                        dialog.dismiss();

                    }
                });

        alertDialog.setNeutralButton(R.string.remind_later_text,
                new DialogInterface.OnClickListener() {
                    public void onClick(DialogInterface dialog, int which) {
                        dialog.dismiss();
                    }
                });

        alertDialog.setNegativeButton(R.string.no_thanks_text,
                new DialogInterface.OnClickListener() {
                    public void onClick(DialogInterface dialog, int which) {
                        if (editor != null) {
                            editor.putBoolean("dontshowagain", true);
                            editor.commit();
                        }
                        dialog.dismiss();
                    }
                });

        return alertDialog.create();

    }

person suresh cheemalamudi    schedule 08.02.2013    source источник


Ответы (4)


Вместо:

AlertDialog.Builder alertDialog = new AlertDialog.Builder(
    new ContextThemeWrapper(MainActivity.context, R.style.AboutDialog));

Попробуй это:

AlertDialog.Builder alertDialog = new AlertDialog.Builder(this, R.style.AboutDialog);

ПРИМЕЧАНИЕ. Это доступно только для API 11 (Android 3.0) и выше.

Если вам нужно поддерживать Android ‹ 3.0, вам, вероятно, придется создать собственный диалог (вместо использования AlertDialog

EDIT Добавлен действительно грязный хак на основе отражения

Если вы действительно застряли и не хотите реализовывать собственный диалог, попробуйте следующее.

После того, как вы создали диалоговое окно и непосредственно перед тем, как вы хотите его вернуть, вместо этого:

return alertDialog.create();

сделай это:

AlertDialog ad = alertDialog.create(); // Create the dialog
// Add listener so we can modify the dialog before it is shown
ad.setOnShowListener(new DialogInterface.OnShowListener() {
    @Override
    public void onShow(DialogInterface dialogInterface) {
        // Set the text color on the dialog title and separator
        setTextColor(dialogInterface, 0xFFE5492A);
    }
});
return ad;

Теперь добавьте этот очень неприятный метод, основанный на отражении:

public void setTextColor(DialogInterface alert, int color) {
    try {
        Class c = alert.getClass();
        Field mAlert = c.getDeclaredField("mAlert");
        mAlert.setAccessible(true);
        Object alertController = mAlert.get(alert);
        c = alertController.getClass();
        Field mTitleView = c.getDeclaredField("mTitleView");
        mTitleView.setAccessible(true);
        Object dialogTitle = mTitleView.get(alertController);
        TextView dialogTitleView = (TextView)dialogTitle;
        // Set text color on the title
        dialogTitleView.setTextColor(color);
        // To find the horizontal divider, first
        //  get container around the Title
        ViewGroup parent = (ViewGroup)dialogTitleView.getParent();
        // Then get the container around that container
        parent = (ViewGroup)parent.getParent();
        for (int i = 0; i < parent.getChildCount(); i++) {
            View v = parent.getChildAt(i);
            if (v instanceof ImageView) {
                // We got an ImageView, that should be the separator
                ImageView im = (ImageView)v;
                // Set a color filter on the image
                im.setColorFilter(color);
            }
        }
    } catch (Exception e) {
        // Ignore any exceptions, either it works or it doesn't
    }
}

Я тестировал это на Android 2.2 и Android 4.0, и это работает. Возможно, это не совсем то, что вы хотите, поэтому вам нужно попробовать. Я не могу гарантировать, что он будет работать на всех устройствах или в будущих версиях Android, так как это во многом зависит от того, как реализован класс AlertDialog (если они изменят это в будущем, это, вероятно, больше не будет работать).

Всего несколько заметок для тех, кому интересно:

  1. Причина, по которой я использую setOnShowListener(), заключается в том, что вы не можете получить доступ к внутренним View объектам, которые использует AlertDialog, пока они не будут надуты. Они не надуваются сразу при создании AlertDialog, это происходит спустя какое-то время. Используя прослушиватель, мы можем получить управление после того, как макет будет раздут, но до того, как будет показано Dialog.

  2. Я использую отражение для доступа к внутренним переменным-членам в реализации AlertDialog. Как только я получу доступ к TextView, содержащему заголовок, мне придется повозиться, чтобы найти горизонтальную линию, которая используется для отделения заголовка от сообщения. Для этого я получаю Layout, окружающий заголовок (это Layout содержит значок предупреждения и текст заголовка). Затем я получаю Layout, который окружает это (это Layout оборачивает значок, текст заголовка и разделитель). Затем я просматриваю все дочерние элементы окружающего макета и устанавливаю цвет для всех ImageView объектов там. Разделитель реализован как ImageView с помощью drawable, поэтому невозможно просто изменить цвет. Примечание. Альтернативой использованию setColorFilter() может быть замена drawable в ImageView на drawable подходящего цвета здесь.

Спасибо за задачу, было весело разобраться :-D

person David Wasser    schedule 08.02.2013
comment
я все еще не могу заставить его работать. это то, что я получаю, если сделать, как вы предложили. i.imgur.com/aEUuCbE.png - person suresh cheemalamudi; 08.02.2013
comment
Добавлено другое решение, основанное на отражении. Надеюсь, это поможет. - person David Wasser; 08.02.2013
comment
спасибо за блестящий лайфхак. Он должен работать. Но после использования этой логики я получаю следующее: i.imgur.com/zCjvsrf.png - person suresh cheemalamudi; 13.02.2013
comment
Вы установили тему для своего приложения или своей активности в манифесте? Какую версию ОС Android вы используете? Это на эмуляторе или устройстве? Если устройство, то какое? - person David Wasser; 13.02.2013
comment
Я. Я установил свою пользовательскую тему в манифесте для стиля панели действий. Я думаю, это создает некоторые проблемы. Я использую ЖБ. на устройстве. Нексус 7 - person suresh cheemalamudi; 13.02.2013
comment
Вы можете попробовать вернуться к AlertDialog.Builder alertDialog = new AlertDialog.Builder(new ContextThemeWrapper(MainActivity.context, R.style.AboutDialog)); и посмотреть, изменится ли что-нибудь. По какой-то причине вы используете другую тему. - person David Wasser; 13.02.2013
comment
OK. Пожалуйста, дайте мне знать результаты. - person David Wasser; 13.02.2013

кстати запоздалый ответ, может кому пригодится. чтобы создать Custom AlertDialog и иметь те же аккуратные кнопки, что и AlertDialog по умолчанию. следуйте простому методу ниже

final AlertDialog.Builder demoDialog = new AlertDialog.Builder(this);
        final LayoutInflater inflator = this.getLayoutInflater();
        final View view = inflator.inflate(R.layout.passcode_req_dialog_template, null);

        demoDialog.setView(view)

            .setPositiveButton(R.string.ok_button_text, new DialogInterface.OnClickListener() {

                @Override
                public void onClick(DialogInterface dialog, int which) {

                }
            })

            .setNegativeButton(R.string.cancel_button_text, new DialogInterface.OnClickListener() {

                @Override
                public void onClick(DialogInterface dialog, int which) {

                }
            });

        final AlertDialog dialog = passwordDialog.create();
        dialog.show();
        dialog.getButton(AlertDialog.BUTTON_POSITIVE).setOnClickListener(new View.OnClickListener() {

            @Override
            public void onClick(View v) {

                //Get the work done here when pressing positive button
                dialog.dismiss(); 
            }
        });

        dialog.getButton(AlertDialog.BUTTON_NEGATIVE).setOnClickListener(new View.OnClickListener() {

            @Override
            public void onClick(View v) {

                //Get the work done here when pressing negative button
                dialog.dismiss();   
            }
        });
person Kirk    schedule 16.12.2013

Попробуйте создать диалоговое окно custom layout for и укажите его layout в диалоговом окне предупреждений, используя

dialog.setContentView(R.layout.customDialogLayout);

Вы можете увидеть этот пример пользовательского диалога.

person Chintan Rathod    schedule 08.02.2013
comment
Я не хотел использовать пользовательский диалог. потому что кнопки в пользовательском диалоге выглядят примерно так: i.imgur.com/aEUuCbE.png . но я хочу, чтобы что-то вроде показанного в вопросе было гладким и аккуратным. Могу ли я добиться этого с помощью пользовательского диалога? - person suresh cheemalamudi; 08.02.2013
comment
конечно вы можете. Вы можете разработать свой макет у любого graphics разработчика, который сообщит вам все необходимые коды цветов, размер текста, цвет текста, границы и т. д. - person Chintan Rathod; 08.02.2013
comment
Можете ли вы показать мне какой-нибудь учебник или пример кода, чтобы получить кнопки в пользовательском макете, как показано в вопросе? - person suresh cheemalamudi; 08.02.2013
comment
Вы можете создать TableLayout с 3 столбцами. У каждого есть TextView с gray фоном. - person Chintan Rathod; 08.02.2013

Вы можете использовать этот проект AlertDialogPro. Включите этот проект в свой и определите свою тему, как показано ниже:

<style name="YourAppTheme.AlertDialogProTheme" parent="AlertDialogProTheme.Holo.Light">
    <!-- Custom the title -->
    <item name="android:windowTitleStyle">@style/YourDialogWindowTitle</item>
    <!-- Change the title line to orange -->
    <item name="adpTitleDividerBackground">#E5492A</item>
</style>

<style name="YourDialogWindowTitle" parent="DialogWindowTitle.Holo.Light">
    <item name="android:textColor">#E5492A</item>
</style>

И укажите эту тему в теме вашего приложения с атрибутом "alertDialogProTheme":

<style name="AppTheme" parent="AppBaseTheme">
  ...
  <item name="alertDialogProTheme">@style/YourAppTheme.AlertDialogProTheme</item>
</style>

Используйте AlertDialogPro.Builder для построения диалога:

AlertDialogPro.Builder builder = new AlertDialogPro.Builder(getContext());
builder.setTitle(R.string.app_name).
    setMessage("Message").
    setPositiveButton("Rate Now", null).
    setNeutralButton("Remind me later", null).
    setNegativeButton("No,thanks", null).
    show();

скриншот

person Feng Dai    schedule 06.10.2014