Как стать автором
Обновить

Пишем свой 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
Теги:
Хабы:
Данная статья не подлежит комментированию, поскольку её автор ещё не является полноправным участником сообщества. Вы сможете связаться с автором только после того, как он получит приглашение от кого-либо из участников сообщества. До этого момента его username будет скрыт псевдонимом.