Pull to refresh

Пишем свой Android Preference

Доброго времени суток. Если вы пишете приложения под Android, то наверняка сталкивались с настройками приложения (Preferences). На первый взгляд всё делается просто (см. сюда), но после беглого знакомства понимаешь что стандартных настроек очень мало. Их всего пять штук:
  • Preference
  • CheckBoxPreference
  • EditTextPreference
  • ListPreference
  • RingtonePreference


Очевидно что всех нужд эти настройки покрыть не могут.

Но тут самое время вспомнить что как то же можно настроить громкость звука или яркость экрана на телефоне — их нельзя настроить с помощью приведённого выше списка настроек! Идем в системные настройки и смотрим как это реализованно: Там есть обычная Preference, по клику на которую вылазит окошко с элементом управления «бегунок»(SeekBar). Впринципе приемлимое решение, но хочется избавится от лишнего окна и перенести бегунок прямо на экран настроек. Беглый поиск не нашёл приемлимых решений, и мы решили написать свой SeekBarPreference.
image

Наш SeekBarPreference должен обладать следущими качествами: он должен показовать текущее значение бегунка «на ходу», и мы хотим использовать его с разными параметрами длинны шага и количества шагов.

Собственно нам понадобится класс, которые отвечает за создание отображения настройки и поведение при перемещении ползунка.

public class SeekBarPreference extends Preference implements
OnSeekBarChangeListener {

private TextView valueTextView;
private int currentValue;
private int max;

//конструктор, вытаскивает спецальные атрибуты настройки
public SeekBarPreference(Context context, AttributeSet attrs) {
super(context, attrs);
max = attrs.getAttributeIntValue(
"http://schemas.android.com/apk/res/com.sample", "max", 99);
currentValue = attrs.getAttributeIntValue(
"http://schemas.android.com/apk/res/com.sample",
"currentValue", 0);
}

//Переопределяем процедуру создания View для этой настройки
@Override
protected View onCreateView(ViewGroup parent) {

RelativeLayout layout = (RelativeLayout) LayoutInflater.from(
getContext())
.inflate(R.layout.seek_bar_preference_layout, null);

((TextView) layout.findViewById(R.id.title)).setText(getTitle());

SeekBar bar = (SeekBar) layout.findViewById(R.id.seekBar);
bar.setMax(max);
bar.setProgress(currentValue);
bar.setOnSeekBarChangeListener(this);

valueTextView = (TextView) layout.findViewById(R.id.value);
valueTextView.setText(currentValue+"");

return layout;
}

//Функция, вызываемая каждый раз при перемещении ползунка
public void onProgressChanged(SeekBar seekBar, int progress,
boolean fromUser) {
valueTextView.setText(progress+"");
valueTextView.invalidate();
}

public void onStartTrackingTouch(SeekBar seekBar) {
}

//Функция, вызываемая после окончания движения пользователем
public void onStopTrackingTouch(SeekBar seekBar) {
currentValue = seekBar.getProgress();
updatePreference(currentValue);
notifyChanged();
}

//Сохранение значения настройки
private void updatePreference(int newValue) {
SharedPreferences.Editor editor = getEditor();
editor.putInt(getKey(), newValue);
editor.commit();
}
}


Для упрощния кода описание отображения было вынесено в отдельный layout:
<RelativeLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="wrap_content">
<TextView
android:id="@+id/title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textSize="20dp" />
<TextView
android:id="@+id/value"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_toRightOf="@+id/title"
android:layout_alignBaseline="@+id/title"
android:paddingLeft="5dp"
android:textSize="18dp" />
<SeekBar
android:id="@+id/seekBar"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:paddingTop="5dp"
android:paddingLeft="10dp"
android:paddingRight="10dp"
android:paddingBottom="3dp"
android:layout_below="@+id/value" />


Layout содержит два текстовых поля — название настройки и текущее значение, и SeekBar.

Для переиспользования этой настройки нам надо определить особые атрибуты — максимальное значение ползунка и начальное положение ползунка. Самый простой способ — сделать специальные атрибуты для нашей настройки. Для этого создадим файл в папке «res/values» файл «attributes.xml»:
<declare-styleable name="SeekBarPreferenceAttrs">
/>
/>
</declare-styleable>


Теперь у нас есть числовые атрибуты которые мы можем использовать при задании настройки:
<com.example.SeekBarPreference
android:key="pref"
android:title="Sample preference"
sample:max="99"
sample:currentValue="30" />


Но чтобы компилятор понял эти атрибуты надо определить из какого пакета их брать. Для этого в начале файла с настройками надо добавить определение пакета:
xmlns:sample="http://schemas.android.com/apk/res/com.example"

После этого можно насладится красивой настройкой без лишних окон.
image
Tags:
Hubs:
You can’t comment this publication because its author is not yet a full member of the community. You will be able to contact the author only after he or she has been invited by someone in the community. Until then, author’s username will be hidden by an alias.