【问题标题】:AppCompatDialog: Impossible to change Text ColorAppCompatDialog:无法更改文本颜色
【发布时间】:2017-03-12 11:38:25
【问题描述】:

我正在努力更改 AppCompat DialogFragments 的 TEXT 颜色。

我的应用程序使用 DARK 主题 (Theme.AppCompat.NoActionBar),但对于对话框,我想要 LIGHT 主题。我正在使用构建工具、支持库和 compileSdkVersion 到 25,这有关系吗?

我可以更改对话框上的所有其他内容(标题、背景、窗口背景)但不能更改主要和重音文本颜色,继续使用深色主题的(白色)设置,导致白色背景上的白色文本。

我在 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 Creation 上手动指定样式:

    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) 手动指定其他奇异常量我在 SO 中遇到了许多帖子,例如

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 版本中使用过这个解决方案,不记得是什么问题,但无论如何,并没有解决当前的问题:(

谁能告诉我这是怎么回事?

【问题讨论】:

  • 只是为了确定:您使用的是android.support.v7.app.AlertDialog,而不是android.app.AlertDialog,是吗?
  • 感谢您的提示。是的,我正在使用 v7.app.AlertDialog !
  • 哦,好吧,我想我明白原因了。您在AlertDialog 上设置了自己的View,因此该主题不适用于Views。即兴发挥,您也许可以将 #2 和 #3 结合起来,得到 LayoutInflater.from()ContextThemeWrapper,而不是 getActivity().getLayoutInflater()
  • 嗯,我什么都想不出来。在我有机会整理答案之前还需要一点时间,所以我会在此期间考虑一下。
  • 是啊!!!!!!!如此简单,如此优雅!这是最好的解决方案。谢谢一百万,先生。

标签: android material-design android-appcompat android-theme


【解决方案1】:

这里的问题是您在AlertDialog 上设置的自定义View。虽然您通常为AlertDialogs 设置了某个主题,但ViewActivity 的主题所夸大,它没有那些被覆盖的颜色属性值。

有几种方法可以解决这个问题。

• 使用自定义R.styleActivityContext 周围创建一个ContextThemeWrapper,并获得LayoutInflater.from()

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

• 正如 OP 所发现的,ruppsAlertDialog.Builder 已经将 alertDialogTheme 包裹在给定的 Context 上,并且其 getContext() 方法将返回适当的 ContextThemeWrapper,这可以用于充气机。

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.BuildergetContext() 方法文档:

/**
* 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">
    ...

• 布局的 ID 可以在 BuildersetView() 调用中传递,而不是自己处理膨胀,它会与 alertDialogTheme 一起膨胀。

但是,使用此方法时,布局中的 View 对象在显示 Dialog 之前将不可用。在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(...);
    ...
}

【讨论】:

  • 一个有趣的副作用是这个视图(及其后代)getContext() 将返回一个包装原始上下文的ContextThemeWrapper。我发现它是因为我在一些点击处理程序中将上下文转换为“活动”。所以就我而言,我不得不在某些地方使用getBaseContext() 来获取原始上下文。
  • 是的,这是有道理的。您确定需要使用Views 中的Context 吗?您应该可以在您的 DialogFragment 类中的任何位置访问 getActivity()
  • 是的,你是对的......问题是,我的 dialogfragment 是视图的通用包装器,有时在对话框中使用,但在更大屏幕的情况下也用于普通布局。无论如何,这是一个具有简单解决方案的边缘案例。不过感谢您的提示!
  • 啊,很好。甚至没有想到那个。它已经为你包装好了。不错。
猜你喜欢
  • 2011-02-01
  • 2012-03-25
  • 1970-01-01
  • 1970-01-01
  • 2012-11-21
  • 1970-01-01
  • 1970-01-01
  • 2023-02-08
  • 1970-01-01
相关资源
最近更新 更多