Как создать пользовательские настройки с помощью библиотеки android.support.v7.preference?

Я хочу поддерживать по крайней мере API 10, я хочу иметь возможность красиво оформить свои предпочтения, я хочу иметь возможность иметь заголовки (или показать PreferenceScreenс). Кажется, что PreferenceActivityне полностью поддерживается AppCompatОкраска не подойдет. Поэтому я пытаюсь использовать AppCompatActivity а также PreferenceFragmentCompat,

public class Prefs extends AppCompatActivity {
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        if (savedInstanceState == null)
            getSupportFragmentManager().beginTransaction()
                    .replace(android.R.id.content, new PreferencesFragment())
                    .commit();
    }

    public static class PreferencesFragment extends PreferenceFragmentCompat {
        @Override public void onCreate(final Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            addPreferencesFromResource(R.xml.preferences);
        }

        @Override
        public void onDisplayPreferenceDialog(Preference preference) {
            // the following call results in a dialogue being shown
            super.onDisplayPreferenceDialog(preference);
        }

        @Override public void onNavigateToScreen(PreferenceScreen preferenceScreen) {
            // I can probably use this to go to to a nested preference screen
            // I'm not sure...
        }
    }
}

Теперь я хочу создать пользовательскую настройку, которая обеспечит выбор шрифта. С PreferenceActivityЯ мог бы просто сделать

import android.preference.DialogPreference;

public class FontPreference extends DialogPreference {

    public FontPreference(Context context, AttributeSet attrs) {super(context, attrs);}

    @Override protected void onPrepareDialogBuilder(Builder builder) {
        super.onPrepareDialogBuilder(builder);
        // do something with builder and make a nice cute dialogue, for example, like this
        builder.setSingleChoiceItems(new FontAdapter(), 0, null);
    }
}

и использовать XML, как это, чтобы отобразить его

<my.app.FontPreference android:title="Choose font" android:summary="Unnecessary summary" />

Но сейчас нет onPrepareDialogBuilder в android.support.v7.preference.DialogPreference, Вместо этого он был перемещен в PreferenceDialogFragmentCompat, Я нашел мало информации о том, как использовать эту вещь, и я не уверен, как перейти от xml к ее отображению. Фрагмент предпочтения v14 имеет следующий код:

public void onDisplayPreferenceDialog(Preference preference) {
    ...

    final DialogFragment f;
    if (preference instanceof EditTextPreference)
        f = EditTextPreferenceDialogFragment.newInstance(preference.getKey());
    ...
    f.show(getFragmentManager(), DIALOG_FRAGMENT_TAG);
}

Я пробовал создавать подклассы android.support.v7.preference.DialogPreference и имея onDisplayPreferenceDialog использовать подобный кусок кода для создания макета FontPreferenceFragment но это терпит неудачу со следующим исключением.

java.lang.IllegalStateException: Target fragment must implement TargetFragment interface

На данный момент я уже слишком глубоко в беспорядке и не хочу копать дальше. Google ничего не знает об этом исключении. В любом случае, этот метод кажется слишком сложным. Итак, каков наилучший способ создания пользовательских настроек с помощью библиотеки android.support.v7.preference?

4 ответа

Решение

Важное примечание: в настоящее время (v23.0.1 из библиотеки v7) все еще есть много проблем с темой PreferenceThemeOverlay (см. Эту проблему). Например, в Lollipop вы получаете заголовки категорий в стиле Holo.

После нескольких разочаровывающих часов мне наконец удалось создать пользовательскую настройку v7. Создание собственного Preference кажется сложнее, чем вы думаете, что это необходимо. Так что не забудьте занять некоторое время.

Сначала вам может быть интересно, почему вы найдете как DialogPreference и PreferenceDialogFragmentCompat для каждого типа предпочтений. Как выясняется, первое фактическое предпочтение, второе DialogFragment где предпочтение будет отображаться в. К сожалению, вы обязаны разделить их обоих.

Не волнуйтесь, вам не нужно менять какой-либо кусок кода. Вам нужно только переместить некоторые методы:

  • Все методы редактирования предпочтений (например, setTitle() или же persist*()) можно найти в DialogPreference учебный класс.
  • Все диалоговые (-редактирующие) методы (onBindDialogView(View) & onDialogClosed(boolean)) были перемещены в PreferenceDialogFragmentCompat,

Вы могли бы хотеть, чтобы ваш существующий класс расширил первый, таким образом, вам не нужно менять на многое, я думаю. Автозаполнение должно помочь вам найти недостающие методы.

После того, как вы выполнили вышеуказанные шаги, пришло время связать эти два класса вместе. В вашем XML-файле вы будете ссылаться на preference-part. Тем не менее, Android еще не знает, какой Fragment он должен надувать, когда ваши предпочтения должны быть. Поэтому вам необходимо переопределить onDisplayPreferenceDialog(Preference):

@Override
public void onDisplayPreferenceDialog(Preference preference) {
    DialogFragment fragment;
    if (preference instanceof LocationChooserDialog) {
        fragment = LocationChooserFragmentCompat.newInstance(preference);
        fragment.setTargetFragment(this, 0);
        fragment.show(getFragmentManager(),
                "android.support.v7.preference.PreferenceFragment.DIALOG");
    } else super.onDisplayPreferenceDialog(preference);
}

а также ваш DialogFragment необходимо обработать "ключ":

public static YourPreferenceDialogFragmentCompat newInstance(Preference preference) {
    YourPreferenceDialogFragmentCompat fragment = new YourPreferenceDialogFragmentCompat();
    Bundle bundle = new Bundle(1);
    bundle.putString("key", preference.getKey());
    fragment.setArguments(bundle);
    return fragment;
}

Это должно делать свое дело. Если вы столкнулись с проблемами, попробуйте взглянуть на существующие подклассы и посмотреть, как Android их решает (в Android Studio: введите имя класса и нажмите Ctrl+b, чтобы увидеть декомпилированный класс). Надеюсь, поможет.

Есть хорошее руководство и проект Github, в котором подробно объясняется, как создать собственный класс предпочтений, расширяющий библиотеку предпочтений поддержки:

Ключевые моменты:

  • Вам понадобится индивидуальный DialogPreference или ListPreference, который управляет внешним видом и функциями строки предпочтений. (Он также может содержать ссылку на макет, который должен отображаться в запущенном диалоговом окне). Добавь этоDialogPreference в ваш файл предпочтений XML.

  • Вам понадобится индивидуальный PreferenceDialogFragmentCompat, который управляет запуском диалогового окна при щелчке по строке предпочтений. Вы можете настроить вид диалога вonBindDialogView().

  • На экране предпочтений, который расширяет PreferenceFragmentCompat, переопределите onDisplayPreferenceDialog() запустить свой обычай PreferenceDialogFragmentCompat.

  • Вы должны расширять только классы поддержки, а не классы платформы. Например, продлитьandroidx.preference.EditTextPreference вместо того android.preference.EditTextPreference

Исключение возникает, когда ваш FontPreferenceFragment не реализует DialogPreference.TargetFragment. Вам нужно убедиться, что ваш фрагмент реализует этот интерфейс.

Уведомление об устаревшемfragment.setTargetFragment(this, 0);К сожалению, пока мы должны оставить этот устаревший метод до тех пор, покаPreferenceDialogFragmentCompat.javaисточник устарел getTargetFragment из onCreate().недавняя фиксация исходного кода Google:

Кроме того, вы можете проверить это в последнем источнике:PreferenceDialogFragmentCompat.java

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