В этой статье я расскажу о том, как сделать так, чтобы элемент в ListView оставался выделенным после того, как пользователь нажмет на него. Дело в том, что по умолчанию в Android каждый дочерний элемент списка выделяется только в тот момент, когда пользователь на него нажимает (или зажимает его). После того как он уберет с него палец — выделение исчезает. Порой в приложении необходимо выделять какой-либо элемент ListView до тех пор, пока пользователь не выберет другой и не нажмет на него. Сделать это  несложно.

Предлагаю для примера создать новый проект с одним Activity. После этого нужно будет добавить в Layout-файл для Activity (по умолчанию — activity_main.xml) компонент ListView и дать ему идентификатор, например, my_listview и добавить свойство android:choiceMode="singleChoice". Также нужно будет создать layout для элементов списка (я решил назвать его listview_item.xml). В него нужно добавить LinearLayout с id item_container и текстовое поле (TextView) с id item_text.

Первым делом я задам значения цветов для выделения элемента. Для этого следует создать файл ресурсов colors.xml в папке res/values и добавить в него следующие строки:

<?xml version="1.0" encoding="utf-8"?>
<resources>
    <color name="orange">#FF8800</color>
    <color name="white">#FFFFFF</color>
    <color name="black">#000000</color>
</resources>

Для работы со списком будет использоваться класс MyAdapter, который расширяет класс BaseAdapter и переопределяет его методы. Его нужно будет создать в классе MainActivity.

Поскольку для версий Android API ниже, чем 11 свойство android:state_activated недоступно, то при отображении view-элемента я буду осуществлять проверку того, какая версия Android установлена на устройстве, и если он будет ниже чем 11, то view будет выделяться следующим образом:

 

if (Build.VERSION.SDK_INT < Build.VERSION_CODES.HONEYCOMB) {
					view.setBackgroundColor(Color.WHITE);
			        textView.setTextColor(Color.BLACK);
		        	if (mListView.isItemChecked(position)) {
		        		view.setBackgroundColor(getResources().getColor(R.color.orange));
			            textView.setTextColor(Color.WHITE);
			        }
			    }

 

Листинг класса MyAdapter:

class MyAdapter extends BaseAdapter {

    	private LayoutInflater mInflater;
    	private ArrayList<String> mItems;
    	public MyAdapter(LayoutInflater inflater, ArrayList<String> items){
    		mInflater = inflater;
    		mItems = items;
    	}
    	
		@Override
		public int getCount() {
			return mItems.size();
		}

		@Override
		public Object getItem(int position) {
			return mItems.get(position);
		}

		@Override
		public long getItemId(int position) {
			return position;
		}

		@Override
		public View getView(int position, View convertView, ViewGroup parent) {
			TextView textView;
			View view;
			ViewHolder holder;
			
			if (convertView == null){
				convertView = mInflater.inflate(R.layout.listview_item, parent, false);
				textView = (TextView) convertView.findViewById(R.id.item_text);
				view = convertView.findViewById(R.id.item_container);
				textView.setText(mItems.get(position));
				holder = new ViewHolder(textView, view);
				convertView.setTag(holder);
				
				
				if (Build.VERSION.SDK_INT < Build.VERSION_CODES.HONEYCOMB) {
					view.setBackgroundColor(Color.WHITE);
			        textView.setTextColor(Color.BLACK);
		        	if (mListView.isItemChecked(position)) {
		        		view.setBackgroundColor(getResources().getColor(R.color.orange));
			            textView.setTextColor(Color.WHITE);
			        }
			    }
			}
			else{
				holder = (ViewHolder) convertView.getTag();
				holder.textView.setText(mItems.get(position));
				
				if (Build.VERSION.SDK_INT < Build.VERSION_CODES.HONEYCOMB) {
					holder.view.setBackgroundColor(Color.WHITE);
			        holder.textView.setTextColor(Color.BLACK);
		        	if (mListView.isItemChecked(position)) {
		        		holder.textView.setTextColor(Color.WHITE);
		        		holder.view.setBackgroundColor(getResources().getColor(R.color.orange));
			        }
			    }
			}
			return convertView;
		}
    	
		class ViewHolder{
			public TextView textView;
			public View view;
			public ViewHolder(TextView tView, View v){
				textView = tView;
				view = v;
			}
		}
    }

 

Теперь в методе onCreate нужно будет создать адаптер и назначить его ListView.  

@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.activity_main);
		mListView = (ListView)findViewById(R.id.my_listview);
		
		ArrayList<String> items = new ArrayList<String>();
		for (int i =0; i<10; i++){
			items.add("Item - " + String.valueOf(i));
		}
		
		MyAdapter adapter = new MyAdapter(getLayoutInflater(), items);
		mListView.setAdapter(adapter);
		mListView.setOnItemClickListener(mItemClickListener);
		
	}

Для того, чтобы элементы списка выделялись после нажатия, нужно будет создать селектор, который будет менять цвет выделения в зависимости от условий. Для этого в папке res нужно создать папку drawable, в которой нужно создать два xml файла с типом selector. Первый нужен для того, чтобы закрашивать фон выделенного View, а второй — чтобы менять цвет текста. Я назвал их item_background_selector.xml и item_text_selector.xml

В первый файл необходимо добавить строки:

<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">  
   <item android:state_activated="true" android:drawable="@color/orange"></item>
   <item android:state_pressed="true" android:drawable="@color/orange"></item>
   <item android:state_pressed="false" android:drawable="@color/white"></item>
</selector>

Вo второй файл:

<?xml version="1.0" encoding="utf-8"?>
  <selector xmlns:android="http://schemas.android.com/apk/res/android">  
  <item android:state_enabled="true" android:state_pressed="true" android:color="@color/white" />
  <item android:state_enabled="true" android:state_focused="true" android:color="@color/white" />
  <item android:state_enabled="true" android:state_selected="true" android:color="@color/white" />
  <item android:state_pressed="false" android:color="@color/black"></item>
</selector>

После этого нужно открыть файл listview_item.xml и добавить следующее свойство для LinearLayout android:background="@drawable/item_background_selector" а для TextView добавить свойство

android:textColor="@drawable/item_text_selector"

Последнее, что осталось сделать — создать и назначить ListView обработчик нажатия на его элементы с указанием, что его нужно выделить.

public OnItemClickListener mItemClickListener = new OnItemClickListener(){

		@Override
		public void onItemClick(AdapterView<?> adapter, View view, int position, long id) {
			mListView.setItemChecked(position, true);
			mListView.setSelected(true);
			
		}
		
	};

А в метод onCreate нужно  добавить строку mListView.setOnItemClickListener(mItemClickListener);

 

Полный листинг класса MainActivity:

public class MainActivity extends Activity {

	private ListView mListView;
	
	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.activity_main);
		mListView = (ListView)findViewById(R.id.my_listview);
		
		ArrayList<String> items = new ArrayList<String>();
		for (int i =0; i<10; i++){
			items.add("Item - " + String.valueOf(i));
		}
		
		MyAdapter adapter = new MyAdapter(getLayoutInflater(), items);
		mListView.setAdapter(adapter);
		mListView.setOnItemClickListener(mItemClickListener);
		
	}

	public OnItemClickListener mItemClickListener = new OnItemClickListener(){

		@Override
		public void onItemClick(AdapterView<?> adapter, View view, int position, long id) {
			mListView.setItemChecked(position, true);
			mListView.setSelected(true);
			
		}
		
	};
	
	@Override
	public boolean onCreateOptionsMenu(Menu menu) {
		// Inflate the menu; this adds items to the action bar if it is present.
		getMenuInflater().inflate(R.menu.main, menu);
		return true;
	}

	
	class MyAdapter extends BaseAdapter {

    	private LayoutInflater mInflater;
    	private ArrayList<String> mItems;
    	public MyAdapter(LayoutInflater inflater, ArrayList<String> items){
    		mInflater = inflater;
    		mItems = items;
    	}
    	
		@Override
		public int getCount() {
			return mItems.size();
		}

		@Override
		public Object getItem(int position) {
			return mItems.get(position);
		}

		@Override
		public long getItemId(int position) {
			return position;
		}

		@Override
		public View getView(int position, View convertView, ViewGroup parent) {
			TextView textView;
			View view;
			ViewHolder holder;
			
			if (convertView == null){
				convertView = mInflater.inflate(R.layout.listview_item, parent, false);
				textView = (TextView) convertView.findViewById(R.id.item_text);
				view = convertView.findViewById(R.id.item_container);
				textView.setText(mItems.get(position));
				holder = new ViewHolder(textView, view);
				convertView.setTag(holder);
				
				
				if (Build.VERSION.SDK_INT < Build.VERSION_CODES.HONEYCOMB) {
					view.setBackgroundColor(Color.WHITE);
			        textView.setTextColor(Color.BLACK);
		        	if (mListView.isItemChecked(position)) {
		        		view.setBackgroundColor(getResources().getColor(R.color.orange));
			            textView.setTextColor(Color.WHITE);
			        }
			    }
			}
			else{
				holder = (ViewHolder) convertView.getTag();
				holder.textView.setText(mItems.get(position));
				
				if (Build.VERSION.SDK_INT < Build.VERSION_CODES.HONEYCOMB) {
					holder.view.setBackgroundColor(Color.WHITE);
			        holder.textView.setTextColor(Color.BLACK);
		        	if (mListView.isItemChecked(position)) {
		        		holder.textView.setTextColor(Color.WHITE);
		        		holder.view.setBackgroundColor(getResources().getColor(R.color.orange));
			        }
			    }
			}
			return convertView;
		}
    	
		class ViewHolder{
			public TextView textView;
			public View view;
			public ViewHolder(TextView tView, View v){
				textView = tView;
				view = v;
			}
		}
    }
}

Запускаем проект, проверяем, все работает! Если у вас возникли вопросы по примеру — задавайте их в комментариях.

Рекомендовано библиотекарем