Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

AppCompatDialog: Impossible to change Text Color

I am struggling with changing the TEXT color of AppCompat DialogFragments.

My App uses a DARK theme (Theme.AppCompat.NoActionBar), but for dialogs I want a LIGHT theme. I am using Build Tools, Support Library and compileSdkVersion to 25, shall it matters.

I am able to change everything else on the dialog (title, background, window background) but not the primary and accented text colors, that keep on using the (white) settings for the dark theme, resulting in white text over white background.

I've tried dozens of solutions in similar questions here in SO, like:

1) The easy one: On the styles.xml:

 <!-- Application theme. -->
<style name="AppTheme" parent="AppBaseTheme">
    <item name="alertDialogTheme">@style/AppCompatAlertDialogStyle</item>
    <item name="android:alertDialogTheme">@style/AppCompatAlertDialogStyle</item>
</style>

<style name="AppCompatAlertDialogStyle" parent="Theme.AppCompat.Light.Dialog.Alert">
    <!-- ignored !!!! -->
    <item name="colorPrimary">#ff0000</item>
    <!-- ignored !!!! -->
    <item name="colorPrimaryDark">#ff0000</item>
    <!-- ignored !!!! -->
    <item name="colorAccent">#ff0000</item>
    <!-- ignored !!!! -->
    <item name="android:textColorPrimary">#F040FF</item>
    <!-- ignored !!!! -->
    <item name="android:textColor">#F040FF</item>

</style>

With this solution, the background and buttons style from AppCompat.Light.Dialog.Alert IS APPLIED, but not the text colors as you can see in the screenshot:

enter image description here

2) Manually specifying the style on the AlertDialog Creation:

    AlertDialog.Builder builder = new AlertDialog.Builder(getActivity(), R.style.AppCompatAlertDialogStyle);
    LayoutInflater inflater = getActivity().getLayoutInflater();
    View hostView = mHostView = inflater.inflate(layoutId, null);

Same problem. Light background, Light text.

3) Using a ContextWrapper:

    ContextThemeWrapper ctw = new ContextThemeWrapper(getActivity(),  R.style.AppCompatAlertDialogStyle);
    AlertDialog.Builder builder = new AlertDialog.Builder(ctw);

Nothing :( Same thing happens

4) Manually specifying other exotic constants I came across the many posts here in SO, like

Theme_DeviceDefault_Light_Dialog_Alert
THEME_DEVICE_DEFAULT_LIGHT

This was just a desperate attempt, but anyways the text is not changed

5) Specifying the style in the fragment rather than on the dialog

    Dialog_Meta newFragment = new Dialog_Meta();
    newFragment.setStyle(DialogFragment.STYLE_NORMAL, R.style.AppCompatAlertDialogStyle);
    newFragment.show(fragmentManager, TAG);

I used this solution time ago in a very old API version, can't remember what was the problem, but anyways, doesn't solve the present issue :(

Can anybody tell me what's going on?

like image 276
rupps Avatar asked Oct 30 '22 17:10

rupps


1 Answers

The problem here is the custom View you're setting on the AlertDialog. Though you've set a certain theme for AlertDialogs in general, that View is being inflated with the Activity's theme, which doesn't have those overridden color attribute values.

There are several ways to solve this.

• Create a ContextThemeWrapper around the Activity's Context with the custom R.style, and obtain the LayoutInflater.from() that.

ContextThemeWrapper ctw = new ContextThemeWrapper(getActivity(), R.style.AppCompatAlertDialogStyle);
LayoutInflater inflater = LayoutInflater.from(getActivity());
View hostView = mHostView = inflater.inflate(layoutId, null);
...

• As discovered by the OP, rupps, the AlertDialog.Builder will already have the alertDialogTheme wrapped on the Context it's given, and its getContext() method will return the appropriate ContextThemeWrapper, which can be used for the Inflater.

AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());
LayoutInflater inflater = LayoutInflater.from(builder.getContext()); // THIS IS THE KEY
View hostView = mHostView = inflater.inflate(layoutId, null);
...

From Google's Documentation of AlertDialog.Builder's getContext() method:

/**
* Returns a {@link Context} with the appropriate theme for dialogs created by this
* Builder.
* Applications should use this Context for obtaining LayoutInflaters for inflating views
* that will be used in the resulting dialogs, as it will cause views to be inflated with
* the correct theme.
*
* @return A Context for built Dialogs.
*/
public Context getContext() {
    ...

• The theme can be set as the android:theme attribute on the root View of the Dialog's layout.

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    android:theme="@style/AppCompatAlertDialogStyle">
    ...

• Rather than handling the inflation yourself, the layout's ID can be passed in the Builder's setView() call, and it will be inflated with the alertDialogTheme.

With this method, however, the View objects from the layout won't be available until the Dialog is shown. In a DialogFragment, this will be in the onStart() method.

@Override
public Dialog onCreateDialog(Bundle savedInstanceState) {
    AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());
    builder.setView(R.layout.dialog);
    return builder.create();
}

@Override
public void onStart() {
    super.onStart();

    final Dialog dialog = getDialog();
    dialog.findViewById(R.id.dialog_button).setOnClickListener(...);
    ...
}
like image 50
Mike M. Avatar answered Nov 11 '22 13:11

Mike M.