AppCompatDialog:无法更改文本颜色
AppCompatDialog: Impossible to change Text Color
我正在努力更改 AppCompat DialogFragments 的文本颜色。
我的应用程序使用 DARK 主题 (Theme.AppCompat.NoActionBar
),但对于对话框我想要一个 LIGHT 主题。我正在使用 Build Tools、Support Library 和 compileSdkVersion 到 25,这很重要。
我可以更改对话框中的其他所有内容(标题、背景、window 背景)但不能更改继续使用的主要和重音文本颜色深色主题的(白色)设置,导致白色背景上的白色文本。
我在 SO 中针对类似问题尝试了数十种解决方案,例如:
1) 简单的:在 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>
使用此解决方案,应用了 AppCompat.Light.Dialog.Alert
中的背景和按钮样式,但未应用您在屏幕截图中看到的文本颜色:
2) 在创建 AlertDialog 时手动指定样式:
AlertDialog.Builder builder = new AlertDialog.Builder(getActivity(), R.style.AppCompatAlertDialogStyle);
LayoutInflater inflater = getActivity().getLayoutInflater();
View hostView = mHostView = inflater.inflate(layoutId, null);
同样的问题。浅色背景,浅色文字。
3) 使用 ContextWrapper:
ContextThemeWrapper ctw = new ContextThemeWrapper(getActivity(), R.style.AppCompatAlertDialogStyle);
AlertDialog.Builder builder = new AlertDialog.Builder(ctw);
没有 :( 同样的事情发生了
4) 手动指定其他奇异常数
Theme_DeviceDefault_Light_Dialog_Alert
THEME_DEVICE_DEFAULT_LIGHT
这只是一次孤注一掷的尝试,但无论如何文本都没有改变
5) 在片段中而不是在对话框中指定样式
Dialog_Meta newFragment = new Dialog_Meta();
newFragment.setStyle(DialogFragment.STYLE_NORMAL, R.style.AppCompatAlertDialogStyle);
newFragment.show(fragmentManager, TAG);
我以前在一个很旧的 API 版本中使用过这个解决方案,不记得是什么问题了,但无论如何,没有解决现在的问题:(
谁能告诉我这是怎么回事?
这里的问题是您在 AlertDialog
上设置的自定义 View
。虽然您通常为 AlertDialog
设置了某个主题,但 View
正在被 Activity
的主题夸大,它没有那些覆盖的颜色属性值。
有几种方法可以解决这个问题。
• 在 Activity
的 Context
周围用自定义 R.style
创建一个 ContextThemeWrapper
,并获得 LayoutInflater.from()
那。
ContextThemeWrapper ctw = new ContextThemeWrapper(getActivity(), R.style.AppCompatAlertDialogStyle);
LayoutInflater inflater = LayoutInflater.from(getActivity());
View hostView = mHostView = inflater.inflate(layoutId, null);
...
• 正如 OP rupps 所发现的那样,AlertDialog.Builder
已经将 alertDialogTheme
包裹在给定的 Context
上,并且其 getContext()
方法将 return 适当的 ContextThemeWrapper
,可用于 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);
...
来自 Google 的 AlertDialog.Builder
的 getContext()
方法的文档:
/**
* 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() {
...
• 主题可以设置为 Dialog
布局的根 View
上的 android:theme
属性。
<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">
...
• 不用自己处理 inflation,布局的 ID 可以在 Builder
的 setView()
调用中传递,它会随着 alertDialogTheme
.
但是,使用此方法时,在显示 Dialog
之前,布局中的 View
对象将不可用。在 DialogFragment
中,这将在 onStart()
方法中。
@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(...);
...
}
我正在努力更改 AppCompat DialogFragments 的文本颜色。
我的应用程序使用 DARK 主题 (Theme.AppCompat.NoActionBar
),但对于对话框我想要一个 LIGHT 主题。我正在使用 Build Tools、Support Library 和 compileSdkVersion 到 25,这很重要。
我可以更改对话框中的其他所有内容(标题、背景、window 背景)但不能更改继续使用的主要和重音文本颜色深色主题的(白色)设置,导致白色背景上的白色文本。
我在 SO 中针对类似问题尝试了数十种解决方案,例如:
1) 简单的:在 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>
使用此解决方案,应用了 AppCompat.Light.Dialog.Alert
中的背景和按钮样式,但未应用您在屏幕截图中看到的文本颜色:
2) 在创建 AlertDialog 时手动指定样式:
AlertDialog.Builder builder = new AlertDialog.Builder(getActivity(), R.style.AppCompatAlertDialogStyle);
LayoutInflater inflater = getActivity().getLayoutInflater();
View hostView = mHostView = inflater.inflate(layoutId, null);
同样的问题。浅色背景,浅色文字。
3) 使用 ContextWrapper:
ContextThemeWrapper ctw = new ContextThemeWrapper(getActivity(), R.style.AppCompatAlertDialogStyle);
AlertDialog.Builder builder = new AlertDialog.Builder(ctw);
没有 :( 同样的事情发生了
4) 手动指定其他奇异常数
这只是一次孤注一掷的尝试,但无论如何文本都没有改变 5) 在片段中而不是在对话框中指定样式 我以前在一个很旧的 API 版本中使用过这个解决方案,不记得是什么问题了,但无论如何,没有解决现在的问题:( 谁能告诉我这是怎么回事?Theme_DeviceDefault_Light_Dialog_Alert
THEME_DEVICE_DEFAULT_LIGHT
Dialog_Meta newFragment = new Dialog_Meta();
newFragment.setStyle(DialogFragment.STYLE_NORMAL, R.style.AppCompatAlertDialogStyle);
newFragment.show(fragmentManager, TAG);
这里的问题是您在 AlertDialog
上设置的自定义 View
。虽然您通常为 AlertDialog
设置了某个主题,但 View
正在被 Activity
的主题夸大,它没有那些覆盖的颜色属性值。
有几种方法可以解决这个问题。
• 在 Activity
的 Context
周围用自定义 R.style
创建一个 ContextThemeWrapper
,并获得 LayoutInflater.from()
那。
ContextThemeWrapper ctw = new ContextThemeWrapper(getActivity(), R.style.AppCompatAlertDialogStyle);
LayoutInflater inflater = LayoutInflater.from(getActivity());
View hostView = mHostView = inflater.inflate(layoutId, null);
...
• 正如 OP rupps 所发现的那样,AlertDialog.Builder
已经将 alertDialogTheme
包裹在给定的 Context
上,并且其 getContext()
方法将 return 适当的 ContextThemeWrapper
,可用于 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);
...
来自 Google 的 AlertDialog.Builder
的 getContext()
方法的文档:
/**
* 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() {
...
• 主题可以设置为 Dialog
布局的根 View
上的 android:theme
属性。
<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">
...
• 不用自己处理 inflation,布局的 ID 可以在 Builder
的 setView()
调用中传递,它会随着 alertDialogTheme
.
但是,使用此方法时,在显示 Dialog
之前,布局中的 View
对象将不可用。在 DialogFragment
中,这将在 onStart()
方法中。
@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(...);
...
}