В предыдущей публикации рассматривалась стилизация внешнего вида 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);
    }
}

 

Запускаем, проверяем. Все работает!