Настройте диалоги androidx.preference, чтобы они соответствовали вашему материалу.
У меня есть два приложения, содержащие раздел настроек, и я использую библиотеку настроек, последнюю версию, доступную на момент написания:
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>
Может быть, это просто вопрос ожидания ?
4 ответа
На данный момент диалоги предпочтений все еще используют
AlertDialog
чтобы раздуть вид. Вот что я определил в своем
styles.xml
чтобы применить к ним тему диалога Material3:
ПРИМЕЧАНИЕ. Это охватывает большую часть стилей MaterialAlertDialog, но вам все равно потребуется определить другие, такие как радиус угла и цвета фона/текста.
<item name="alertDialogTheme">@style/ThemeOverlay.Material3.MaterialAlertDialog</item>
<item name="dialogCornerRadius">28dp</item>
После дальнейшего расследования я обнаружил, что на сегодняшний день единственный способ правильно оформить диалоги настроек — это использовать небольшую вариацию решения, предложенного @Patrick:
- Создайте рисуемый объект, я назвал его dialog_bg_monet.xml, содержащий этот список слоев:
<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>
Результат:
Приложение на скриншоте выше имеет открытый исходный код, вы можете увидеть полный код здесь.
Вот что я сделал.
Создайте класс MaterialListPreference, расширяющий ListPreferenceDialogFragmentCompat.
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.