Применение темы AppCompat к индивидуальным предпочтениям в PreferenceFragment
Я боролся, пытаясь заставить мою PreferenceFragment
иметь ту же материальную тему и стиль (через AppCompat), что и остальная часть моего приложения. PreferenceFragment
, который я использую для управления всеми настройками моего приложения, показан ниже:
![enter image description here]()
Как вы можете видеть на скриншоте выше, я смог настроить PreferenceFragment
с помощью colorAccent
, colorPrimary
и нескольких других атрибутов. Моя тема для PreferenceFragment
выглядит следующим образом:
<style
name="settingsTheme"
parent="Theme.AppCompat.Light.DarkActionBar">
<item name="colorPrimary">@color/blue_grey_500</item>
<item name="colorAccent">@color/blue_grey_500</item>
<item name="android:textColor">@color/black_text_alt</item>
<item name="android:textColorSecondary">@color/black_secondary_text</item>
</style>
Однако, несмотря на все мои усилия, я не могу применять темы к отдельным элементам в моем PreferenceFragment
, например ListPreference
и EditTextPreference
; все предпочтения по-прежнему сохраняют стандартную тему AppCompat:
![enter image description here]()
Я нашел 2-летний пост, который обсуждает эту проблему, хотя и без реального решения: Как применить тему к <PreferenceScreen> элементы <PreferenceCategory>
Мне интересно, смог ли кто-нибудь успешно применить темы к предпочтениям, поскольку AppComat V21 был выпущен. Если нет, существуют ли какие-либо жизнеспособные обходные пути, которые можно использовать для применения пользовательских тем к индивидуальным предпочтениям?
Ответы
Ответ 1
ОБНОВЛЕНИЕ: Я создал библиотеку для борьбы с проблемой (использует AppCompat r22): https://github.com/consp1racy/android-support-preference
ListPreference
extends DialogPreference
, который использует этот фрагмент кода для создания диалога:
mBuilder = new AlertDialog.Builder(context)
.setTitle(mDialogTitle)
.setIcon(mDialogIcon)
.setPositiveButton(mPositiveButtonText, this)
.setNegativeButton(mNegativeButtonText, this);
Как вы видите, конструктор AlertDialog.Builder
не поставляется со вторым необязательным параметром int theme
. Это означает, что диалоговое окно будет отображаться независимо от вашей темы активности в своем атрибуте android:alertDialogTheme
.
Теперь вам нужно создать настраиваемую тему для своего диалога, которая получается из Theme.AppCompat.Dialog
следующим образом:
<style name="Theme.YourApp.Dialog.Alert" parent="Theme.AppCompat.Light.Dialog">
<item name="android:windowBackground">@android:color/transparent</item>
<item name="android:windowContentOverlay">@null</item>
<item name="android:windowMinWidthMajor">@android:dimen/dialog_min_width_major</item>
<item name="android:windowMinWidthMinor">@android:dimen/dialog_min_width_minor</item>
<item name="colorAccent">@color/accent_yourapp</item>
<item name="colorPrimary">@color/primary_yourapp</item>
<item name="colorPrimaryDark">@color/primary_dark_yourapp</item>
</style>
Проблема 1: Вышеупомянутое решение не будет работать для RingtonePreference
, потому что оно не распространяется на ListPreference
, но вызывает намерение выбора рингтонов, поэтому оно всегда соответствует тематике системы. Проверьте этот ответ:
Тема RingtonePreference Итак, мы можем отметить это как решение.
Проблема 2: В диалоговом окне AppCompat отсутствует название. И пока я не нашел способа исправить это. Верно, что я не выгляжу достаточно тяжело. Пусть игнорируется отсутствие заголовка в качестве незначительной проблемы.
Проблема 3: Выводные кнопки переключателя не изменяются, поэтому графики несовместимы между пассивным и активным (цветным) состоянием - все они окрашены (не только одно нажатие), либо все серый. Теперь это действительно раздражает
Проблемы 2 и 3 заставили меня пойти другим путем - моя тема диалога выглядит так на API 14 +
<style name="Theme.MyApp.Dialog.Alert" parent="android:Theme.DeviceDefault.Light.Dialog.MinWidth">
<item name="android:windowBackground">@android:color/transparent</item>
<item name="android:windowContentOverlay">@null</item>
</style>
и так далее на API 21 +
<style name="Theme.YourApp.Dialog.Alert" parent="android:Theme.DeviceDefault.Light.Dialog.MinWidth">
<item name="android:colorPrimary">@color/primary_yourapp</item>
<item name="android:colorPrimaryDark">@color/primary_dark_yourapp</item>
<item name="android:colorAccent">@color/accent_yourapp</item>
</style>
Эти значения были экспериментально получены путем сканирования через исходные файлы платформы и тестирования.
Дело в том, что единственное надежное решение, похоже, использует тему диалога по умолчанию для устройства. Единственный выбор перед Lollipop - легкий или темный вариант. На Lollipop это будет работать по назначению и запрошено.
EDIT:. Поскольку appcompat-v7-r21.1.0 вы можете использовать AppCompatDialog
, который является тематическим вариант нативного AlertDialog
.
Вы можете использовать предоставленный AlertDialog.Builder
(не путать с его родным экземпляром) для создания своих экземпляров.
Ответ 2
DialogPreference
использует android.app.AlertDialog.Builder
напрямую, поэтому было бы невозможно переключить отображаемое диалоговое окно на конструкцию материала для всех уровней API (что требует использования android.support.v7.widget.AlertDialog.Builder
).
Я считаю, что единственным вариантом на данный момент является расширение и переопределение логики создания диалога в DialogPreference
или его подклассах (и использование рефлексии для работы с частными помощниками, если это необходимо). Посмотрите reddit thread и пример AppCompatListPreference
сделал автор этой темы.
Ответ 3
Взяв подсказки из уже полученных ответов, я установил в манифесте настраиваемую тему для активности "Настройки", потому что необходимо удалить фон границы вокруг Диалога, который появляется, используя прозрачный фон, это только для API < 21:
AndroidManifest.xml
<application
android:name=".MyApplication"
...
android:theme="@style/AppTheme">
...
<activity
android:name=".ui.SettingsActivity"
...
android:theme="@style/AppTheme.Settings">
</activity>
</application>
значения/style.xml
<!-- Application theme -->
<style name="AppTheme" parent="AppTheme.Base">
<!-- All customizations that are NOT specific to a particular API-level can go here. -->
</style>
<style name="AppTheme.Base" parent="Theme.AppCompat.Light.NoActionBar">
...
<item name="android:alertDialogTheme">@style/AppTheme.AlertDialog</item>
</style>
<!-- Must be different because of transparent background -->
<style name="AppTheme.Settings" parent="AppTheme.Base">
<item name="android:alertDialogTheme">@style/AppTheme.SettingsAlertDialog</item>
</style>
<style name="AppTheme.AlertDialog" parent="Theme.AppCompat.Light.Dialog.Alert">
<item name="android:windowMinWidthMajor">@android:dimen/dialog_min_width_major</item>
<item name="android:windowMinWidthMinor">@android:dimen/dialog_min_width_minor</item>
<item name="android:windowContentOverlay">@null</item>
<item name="colorAccent">@color/accent_light</item>
<item name="colorControlActivated">@color/accent_light</item>
<item name="colorControlHighlight">@color/primary_highlight</item>
</style>
<style name="AppTheme.SettingsAlertDialog" parent="Theme.AppCompat.Light.Dialog.Alert">
<item name="android:windowMinWidthMajor">@android:dimen/dialog_min_width_major</item>
<item name="android:windowMinWidthMinor">@android:dimen/dialog_min_width_minor</item>
<item name="android:windowBackground">@android:color/transparent</item>
<item name="android:windowContentOverlay">@null</item>
<item name="colorAccent">@color/accent_light</item>
<item name="colorControlActivated">@color/accent_light</item>
<item name="colorControlHighlight">@color/primary_highlight</item>
</style>
Наконец, для значений v21/style.xml нормальный диалог, если вы не поместите это в диалоги v21, будет прозрачным.
<style name="AppTheme.Settings" parent="AppTheme.Base">
<item name="android:alertDialogTheme">@style/AppTheme.AlertDialog</item>
</style>
На самом деле у меня проблема с настройкой цветов непосредственно из атрибутов Theme:? android: colorAccent вместо моего фиксированного цвета @color/accent_light.
Ответ 4
Вы должны проверить этот Gist о том, как разные компоненты используют атрибуты цвета темы. Возможно, вам потребуется добавить следующие атрибуты в вашу тему, чтобы получить необходимый эффект:
<item name="colorControlNormal">@color/x_color</item>
<item name="colorControlActivated">@color/y_color</item>
<item name="colorControlHighlight">@color/z_color</item>