我有两个包含首选项部分的应用程序,并且我正在使用首选项库,这是撰写本文时可用的最新版本:
implementation "androidx.preference:preference:1.2.0-rc01"
现在,我将我的应用程序主题化为使用并遵循新的 Material3(或 Material You)主题,但我面临的一个问题是,虽然普通对话框的主题正确,但首选项部分中的对话框仅部分主题化(拐角半径)。他们显然不使用新样式,这种不一致快要了我的命:D
目前,我没有找到一种方法来为它们设置主题,而无需奇怪的解决方法,所以我将不胜感激。这是我目前的对话框样式
<!-- Dialog theme -->
<style name="ThemeOverlay.App.MaterialAlertDialog" parent="ThemeOverlay.Material3.MaterialAlertDialog">
<item name="colorOnSurface">?colorAccent</item>
<item name="alertDialogStyle">@style/MaterialAlertDialog.App</item>
<item name="dialogCornerRadius">@dimen/bottom_sheet_corners</item>
</style>
<!-- Note: shape appearance doesn't work with the preference dialogs (they're not material) -->
<style name="MaterialAlertDialog.App" parent="MaterialAlertDialog.Material3">
<item name="shapeAppearance">@style/ShapeAppearance.App.MediumComponent</item>
<item name="shapeAppearanceOverlay">@null</item>
</style>
也许这只是等待的问题?
目前,首选项对话框仍然使用
AlertDialog
来膨胀视图。以下是我在 styles.xml
中定义的内容,以将 Material3 对话框主题应用于它们:
注意: 这涵盖了大部分 MaterialAlertDialog 样式,但您仍然需要定义其他样式,例如角半径和背景/文本颜色。
<item name="alertDialogTheme">@style/ThemeOverlay.Material3.MaterialAlertDialog</item>
<item name="dialogCornerRadius">28dp</item>
经过进一步调查,我发现,截至今天,正确设置首选项对话框主题的唯一方法是使用向 @Patrick 提出的解决方案的细微变化:
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
<item>
<shape>
<solid android:color="?attr/colorSurface" />
<corners
android:bottomLeftRadius="@dimen/yourcorners"
android:bottomRightRadius="@dimen/yourcorners"
android:topLeftRadius="@dimen/yourcorners"
android:topRightRadius="@dimen/yourcorners" />
</shape>
</item>
<item>
<shape>
<solid android:color="@color/m3_popupmenu_overlay_color" />
<corners
android:bottomLeftRadius="@dimen/yourcorners"
android:bottomRightRadius="@dimen/yourcorners"
android:topLeftRadius="@dimen/yourcorners"
android:topRightRadius="@dimen/yourcorners" />
</shape>
</item>
</layer-list>
当然,请确保在尺寸中或直接在文件中定义自定义边框半径。忽略警告。没有别的办法了
<!-- Preference dialog theme -->
<style name="ThemeOverlay.App.MaterialAlertDialog.Monet" parent="ThemeOverlay.Material3.MaterialAlertDialog">
<item name="alertDialogStyle">@style/MaterialAlertDialog.App</item>
<item name="dialogCornerRadius">@dimen/yourcorners</item>
<item name="android:background">@drawable/dialog_bg_monet</item>
</style>
<item name="materialAlertDialogTheme">@style/ThemeOverlay.App.MaterialAlertDialog.Monet</item>
<item name="alertDialogTheme">@style/ThemeOverlay.App.MaterialAlertDialog.Monet</item>
结果:
编辑:这种方法会导致上下文菜单(长按文本时弹出的复制/粘贴菜单)出现错误。解决这个问题的方法很简单,就在这个问题
这就是我所做的。
创建一个扩展 ListPreferenceDialogFragmentCompat 的 MaterialListPreference 类
class MaterialListPreference : ListPreferenceDialogFragmentCompat() {
private var mWhichButtonClicked = 0
override fun onCreateDialog(savedInstanceState: Bundle?): Dialog {
val context: Context? = activity
mWhichButtonClicked = DialogInterface.BUTTON_NEGATIVE
val builder = MaterialAlertDialogBuilder(requireActivity()).setTitle(preference.dialogTitle).setIcon(preference.dialogIcon)
.setPositiveButton(preference.positiveButtonText, this)
.setNegativeButton(preference.negativeButtonText, this)
val contentView = context?.let { onCreateDialogView(it) }
if (contentView != null) {
onBindDialogView(contentView)
builder.setView(contentView)
} else {
builder.setMessage(preference.dialogMessage)
}
onPrepareDialogBuilder(builder)
return builder.create()
}
override fun onClick(dialog: DialogInterface, which: Int) {
mWhichButtonClicked = which
}
override fun onDismiss(dialog: DialogInterface) {
onDialogClosedWasCalledFromOnDismiss = true
super.onDismiss(dialog)
}
private var onDialogClosedWasCalledFromOnDismiss = false
override fun onDialogClosed(positiveResult: Boolean) {
if (onDialogClosedWasCalledFromOnDismiss) {
onDialogClosedWasCalledFromOnDismiss = false
super.onDialogClosed(mWhichButtonClicked == DialogInterface.BUTTON_POSITIVE)
} else {
super.onDialogClosed(positiveResult)
}
}
}
在 SettingsFragment 上覆盖 onDisplayPreferenceDialog
override fun onDisplayPreferenceDialog(preference: Preference) {
if (preference is ListPreference) {
showListPreferenceDialog(preference)
} else {
super.onDisplayPreferenceDialog(preference)
}
}
private void showListPreferenceDialog(ListPreference preference) {
DialogFragment dialogFragment = new MaterialListPreference();
Bundle bundle = new Bundle(1);
bundle.putString("key", preference.getKey());
dialogFragment.setArguments(bundle);
dialogFragment.setTargetFragment(this, 0);
dialogFragment.show(getParentFragmentManager(), "androidx.preference.PreferenceFragment.DIALOG");
}
仅此而已。现在您将看到“您列出的材料”首选项。
另一个解决方案(更彻底,但需要更少的代码更改)是从 https://github.com/androidx/androidx/tree/androidx-main/preference 创建首选项库的本地副本作为您的模块中的模块项目,然后修改类 PreferenceDialogFragmentCompat 以使用 MaterialAlertDialogBuilder。