Настройте диалоги 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:

  1. Создайте рисуемый объект, я назвал его 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>

Конечно, не забудьте определить пользовательский радиус границы в размерах или непосредственно в файле. Не обращайте внимания на предупреждение. Другого пути нет.

  1. Создайте стиль для диалогов, как показано ниже:
          <!-- 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>
  1. Примените этот стиль в своей основной теме
      <item name="materialAlertDialogTheme">@style/ThemeOverlay.App.MaterialAlertDialog.Monet</item>
<item name="alertDialogTheme">@style/ThemeOverlay.App.MaterialAlertDialog.Monet</item>

Результат:

Приложение на скриншоте выше имеет открытый исходный код, вы можете увидеть полный код здесь.

Вот что я сделал.

  1. Создайте класс 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)
           }
       }
    }
    
  2. В 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");
    }
    
  3. Вот и все. Теперь вы увидите предпочтение «Материал, который вы выберете».

Другое решение (более радикальное, но требующее меньшего количества изменений кода) — создать локальную копию библиотеки настроек из https://github.com/androidx/androidx/tree/androidx-main/preference в качестве модуля в вашем проекте, а затем измените класс PreferenceDialogFragmentCompat, чтобы использовать MaterialAlertDialogBuilder.

Другие вопросы по тегам