В предыдущей публикации рассматривалась стилизация внешнего вида PreferenceActivity. В этой же статье я хочу рассказать о том, как можно изменить внешний вид ListPreference на свой собственный. Давайте приступим к работе.
Для начала, как отмечалось в предыдущей статье, нужно будет создать приложение с одним главным Activity, в котором будет находиться кнопка вызова PreferenceActivity. По традиции название класса для главного Activity останется неизменным – MainActivity, ну а PreferenceActivity я назову PrefsActivity. Убедитесь в том, что эти два Activity прописаны в манифесте. Подбробно рассматривать это процедуру я не буду, поскольку это было расписано в предыдущей статье. При этом следует обратить особое внимание на то, что ListPreference будет нами создаваться программно, поэтому в методе onCreate класса PrefsActivity следует оставить только эту строку super.onCreate(savedInstanceState);.
Теперь приступим к самому интересному – будем создавать свой ListPreference с кастомным фоном. Для начала нужно скачать текстуру для фона отсюда и поместить ее в папку res/drawable нашего проекта. Если такой папки не существует – ее нужно создать.
Для того, чтобы поменять внешний вид ListPreference, нужно создать свой собственный класс, который будет расширять функционал класса ListPreference. Я назову этот класс CustomListPreference. Пока что он будет содержать только два конструктора и иметь поле со ссылкой на LayoutInflater, необходимой для создания элементов списка и массива данных типа CharSequence (для чего он нужен я объясню позже), а также ссылку на Context для создания адаптера для списка. Вот как это будет выглядеть:
import android.content.Context; import android.preference.ListPreference; import android.util.AttributeSet; import android.view.LayoutInflater; public class CustomListPreference extends ListPreference { private LayoutInflater mInflater; private CharSequence[] entries; private Context mContext; public CustomListPreference(Context context) { super(context); mInflater = LayoutInflater.from(context); mContext = context; } public CustomListPreference(Context ctxt, AttributeSet attrs) { super(ctxt, attrs); } }
Теперь необходимо создать класс-адаптер для списка, в котором будем указывать, какой фон должен быть у его элементов. Для этого следует создать в CustomListPreference новый класс — назовем его CustomListAdapter,расширяющий класс BaseAdapter. Опускаю пример адаптера реализации паттерна ViewHolder. Но в рабочих приложениях, с целью повышения их быстродействия, Google настоятельно рекомендует этот паттерн использовать. Более детально об этом можно прочитать здесь.
Листинг класса CustomListAdapter:
private class CustomListAdapter extends BaseAdapter { public CustomListAdapter(Context context) { } public int getCount() { return entries.length; } public Object getItem(int position) { return position; } public long getItemId(int position){ return position; } @Override public View getView(final int position, View convertView, ViewGroup parent) { View row = convertView; TextView tView; if(row == null) { row = mInflater.inflate(android.R.layout.simple_list_item_single_choice, parent, false); tView = (TextView)row.findViewById(android.R.id.text1); } else tView = (TextView)row.findViewById(android.R.id.text1); row.setBackgroundResource(R.drawable.background); tView.setText(entries[position]); return row; } }
В методе getView с помощью LayoutInflater-a мы создаем view-представление для элемента списка, после чего указываем ему, какой фон следует использовать и возвращаем наш кастомный элемент. Следует обратить внимание на то, что в текстовое поле передается значение из массива entries, который был объявлен ранее в качестве поля нашего класса. Что же это за массив? ListPreference должен содержать в себе два массива текстовых данных. Один массив содержит в себе «человекопонятные» текстовые данные. Они будут отображаться в качестве содержимого списка. Он то нам и нужен для того, чтобы задать текст для текстовых полей. В данный момент этот массив является нулевым и, соответственно, нам нужно его проинициализировать, а также назначить нашему списку адаптер. Для начала – следует добавить в класс CustomListPreference поле, ссылающееся на адаптер private CustomListAdapter mAdapter;
и переопределить несколько методов из класса ListPreference
Листинг этих методов:
@Override protected void onPrepareDialogBuilder(Builder builder) { entries = getEntries(); mAdapter = new CustomListAdapter(mContext); builder.setAdapter(mAdapter, this); builder.setNegativeButton(null, null); super.onPrepareDialogBuilder(builder); } @Override protected void onDialogClosed(boolean positiveResult) { super.onDialogClosed(positiveResult); setSummary(getSummary()); } @Override public CharSequence getSummary() { try{ int pos = findIndexOfValue(getValue()); return getEntries()[pos]; } catch(Exception e){return "";} }
Все, на этом реализация класса CustomListPreference завершена и нам необходимо добавить его в окно настроек. Листинг класса CustomListPreference.
Теперь следует програмно создать список в PrefsActivity. Для начала нужно создать два массива с текстовыми данными для списка, затем в методе onCreate создать корневой экран для настроек, кастомизированный список, назначить списку текстовые данные и добавить его в экран настроек.
Листинг класса PrefsActivity:
import android.os.Bundle; import android.preference.PreferenceActivity; import android.preference.PreferenceScreen; public class PrefsActivity extends PreferenceActivity { private String [] entries = new String[]{"One", "Two", "Three"}; private String [] entryValues = new String [] {"one_key", "two_key", "three_key"}; @SuppressWarnings("deprecation") @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); PreferenceScreen rootScreen = getPreferenceManager().createPreferenceScreen(this); setPreferenceScreen(rootScreen); CustomListPreference list = new CustomListPreference(this); list.setKey("list"); list.setTitle("List"); list.setSummary("Description of list"); list.setEntries(entries); list.setEntryValues(entryValues); rootScreen.addPreference(list); } }
Запускаем, проверяем. Все работает!