Файл: Занятие 15 Адаптеры и списки в Android Studio Время 2 часа.docx

ВУЗ: Не указан

Категория: Не указан

Дисциплина: Не указана

Добавлен: 08.11.2023

Просмотров: 91

Скачиваний: 3

ВНИМАНИЕ! Если данный файл нарушает Ваши авторские права, то обязательно сообщите нам.
Теперь определим в коде MainActivity обработку выбора элементов списка:package com.example.myapplication57;import androidx.appcompat.app.AppCompatActivity;import android.os.Bundle;import android.util.SparseBooleanArray;import android.view.View;import android.widget.AdapterView;import android.widget.ArrayAdapter;import android.widget.ListView;import android.widget.TextView;import android.widget.AdapterView.OnItemClickListener;public class MainActivity extends AppCompatActivity {String[] countries = { "Смоленск", "Вологда", "Москва", "Сан-Хосе", "Чикаго"};TextView selection;ListView countriesList;@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);// получаем элемент TextViewselection = (TextView) findViewById(R.id.selection);// получаем элемент ListViewcountriesList = (ListView) findViewById(R.id.countriesList);// создаем адаптерArrayAdapter adapter = new ArrayAdapter(this,
android.R.layout.simple_list_item_multiple_choice, countries);
// устанавливаем для списка адаптер
countriesList.setAdapter(adapter);
// добвляем для списка слушатель
countriesList.setOnItemClickListener(new OnItemClickListener(){
@Override
public void onItemClick(AdapterView> parent, View v, int position, long id)
{
SparseBooleanArray sp=countriesList.getCheckedItemPositions();

String selectedItems="";
for(int i=0;i < countries.length;i++)
{
if(sp.get(i))
selectedItems+=countries[i]+",";
}
// установка текста элемента TextView
selection.setText("Выбрано: " + selectedItems);
}
});
}


Ресурс android.R.layout.simple_list_item_multiple_choice представляет стандартную разметку, предоставляемую фреймворком, для создания списка с множественным выбором.

А при выборе элементов мы получаем все выбранные позиции в объект SparseBooleanArray, затем пробегаемся по всему массиву, и если позиция элемента в массиве есть в SparseBooleanArray, то есть она отмечена, то добавляем отмеченный элемент в строку, результат см. рис.5.


Рис. 5 – Множественный выбор

1.5.Добавление и удаление в ListView (App_58)


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

Для управления данными мы можем использовать методы адаптера или напрямую источника данных. Например, с помощью метода add() класса ArrayAdapter можно добавить новый элемент в конец массива-источника данных. Метод insert() позволяет добавить новое значение по определенному индексу, а метод remove() позволяет удалить объект из массива. С помощью метода sort() можно провести сортировку массива

Однако после применения вышеуказанных методов изменения коснутся только массива, выступающего источником данных. Чтобы синхронизировать изменения с элементом ListView, надо вызвать у адаптера метод notifyDataSetChanged().

Например, определим в файле activity_main.xml следующие элементы:

?xml version="1.0" encoding="utf-8"?>
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical" >
android:layout_width="match_parent"
android:layout_height="wrap_content">
android:id="@+id/phone"
android:layout_weight="4"
android:layout_width="0dp"
android:layout_height="wrap_content" />
android:layout_weight="1"
android:text="+"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:onClick="add"/>
android:layout_weight="1"
android:text="-"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:onClick="remove"/>

android:choiceMode="multipleChoice"
android:id="@+id/phonesList"
android:layout_width="match_parent"
android:layout_height="match_parent"/>

Для вывода списка предназначен ListView с возможностью множественного выбора элементов. Для добавления и удаления определены две кнопки. Для ввода нового объекта в список предназначено поле EditText.

Теперь изменим класс MainActivity:

package com.example.myapplication58;

import androidx.appcompat.app.AppCompatActivity;

import android.os.Bundle;

import android.view.View;
import android.widget.AdapterView;
import android.widget.ArrayAdapter;
import android.widget.EditText;
import android.widget.ListView;

import java.util.ArrayList;

public class MainActivity extends AppCompatActivity {

ArrayList phones = new ArrayList();
ArrayAdapter adapter;

ArrayList selectedPhones = new ArrayList();
ListView phonesList;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);

phones.add("iPhone 7");
phones.add("Samsung Galaxy S7");
phones.add("Google Pixel");
phones.add("Huawei P10");
phones.add("HP Elite z3");

phonesList = (ListView) findViewById(R.id.phonesList);
adapter = new ArrayAdapter(this, android.R.layout.simple_list_item_multiple_choice, phones);
phonesList.setAdapter(adapter);

// обработка установки и снятия отметки в списке
phonesList.setOnItemClickListener(new AdapterView.OnItemClickListener(){
@Override
public void onItemClick(AdapterView> parent, View v, int position, long id)
{
// получаем нажатый элемент
String phone = adapter.getItem(position);
if(phonesList.isItemChecked(position)==true){
selectedPhones.add(phone);
}
else{

selectedPhones.remove(phone);
}
}
});
}

public void add(View view){

EditText phoneEditText = (EditText) findViewById(R.id.phone);
String phone = phoneEditText.getText().toString();
if(!phone.isEmpty() && phones.contains(phone)==false){
adapter.add(phone);
phoneEditText.setText("");
adapter.notifyDataSetChanged();
}
}
public void remove(View view){
// получаем и удаляем выделенные элементы
for(int i=0; i< selectedPhones.size();i++){
adapter.remove(selectedPhones.get(i));
}
// снимаем все ранее установленные отметки
phonesList.clearChoices();
// очищаем массив выбраных объектов
selectedPhones.clear();

adapter.notifyDataSetChanged();
}
}
С добавлением все относительно просто: получаем введенную строку и добавляем в список с помощью метода adapter.add(). Чтобы обновить ListView после добавления вызывается метод adapter.notifyDataSetChanged().

А для удаления создается дополнительный список selectedPhones, который будет содержать выделенные элементы. Для получения выделенных элементов и добавления их в список используется слушатель AdapterView.OnItemClickListener, метод onItemClick() которого вызывается при установке или снятия отметки с элемента, то есть при любом нажатии на элемент.

По нажатию на кнопку удаления пробегаемся по списку выделенных элементов и вызываем для каждого из них метод adapter.remove(). Резульат на вашем устройстве, проведите добавление удаление элементов.


  1. Расширение списков и создание адаптера (App_59)



Обычные списки ListView, использующие стандартные адаптеры ArrayAdapter, хорошо работают с массивами строк. На практике мы будем сталкиваться с более сложными по структуре списками, где один элемент представляет не одну строку, а несколько строк, картинок и других компонентов.

Для создания сложного списка надо переопределить один из используемых адаптеров. Поскольку, как правило, используется ArrayAdapter, то именно его и переопределим.

Но вначале определим модель, данные которой будут отображаться в списке. Для этого добавим в тот же каталог, где находится класс MainActivity, новый класс. Для этого нажмем на данный каталог правой кнопкой мыши и в меню выберем New → Java Class, см. рис.6.



Рис. 6 – Добавление нового класса
В появившемся окне укажем для добавляемого класса имя В появившемся окне укажем для добавляемого класса имя State, см. рис.7..



Рис. 7 – Именование класса
После добавления изменим класс State следующим образом:

public class State {private String name; // название
private String capital; // столица
private int flagResource; // ресурс флага

public State(String name, String capital, int flag){

this.name=name;
this.capital=capital;
this.flagResource=flag;
}

public String getName() {
return this.name;
}

public void setName(String name) {
this.name = name;
}
public String getCapital() {
return this.capital;
}

public void setCapital(String capital) {
this.capital = capital;
}

public int getFlagResource() {
return this.flagResource;
}

public void setFlagResource(int flagResource) {
this.flagResource = flagResource;
}
}
Данный класс хранит два строковых поля - название государства и его столицу, а также числовое поле, которое будет указывать на ресурс изображения из папки drawable, которое будет отображать флаг государства.

Далее добавим в папку res/layout новый файл list_item.xml, который будет представлять разметку одного элемента в списке:




android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:padding="16dp">
android:id="@+id/flag"
android:layout_marginRight="16dp"
android:layout_marginEnd="16dp"
android:layout_width="70dp"
android:layout_height="50dp" />

android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="wrap_content">

android:id="@+id/name"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Название" />

android:id="@+id/capital"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Столица" />




Каждый элемент будет иметь изображение в виде ImageView и два компонента TextView для отображения названия и столицы государства.

После этого добавим в каталог, где находятся классы MainActivity и State, новый класс, который назовем StateAdapter:

import android.content.Context;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ArrayAdapter;
import android.widget.ImageView;
import android.widget.TextView;
import java.util.List;
public class StateAdapter extends ArrayAdapter {

private LayoutInflater inflater;
private int layout;
private List states;

public StateAdapter(Context context, int resource, List states) {
super(context, resource, states);
this.states = states;
this.layout = resource;
this.inflater = LayoutInflater.from(context);
}
public View getView(int position, View convertView, ViewGroup parent) {

View view=inflater.inflate(this.layout, parent, false);

ImageView flagView = (ImageView) view.findViewById(R.id.flag);
TextView nameView = (TextView) view.findViewById(R.id.name);
TextView capitalView = (TextView) view.findViewById(R.id.capital);

State state = states.get(position);

flagView.setImageResource(state.getFlagResource());
nameView.setText(state.getName());
capitalView.setText(state.getCapital());

return view;
}
}
Все взаимодействие со списком здесь будет идти через класс StateAdapter. В конструкторе StateAdapter нам надо передать в конструктор базового класса три параметра:

- контекст, в котором используется класс. В его роли как правило выступает класс Activity;

- ресурс разметки интерфейса, который будет использоваться для создания одного элемента в ListView;

- набор объектов, которые будут выводиться в ListView.

В конструкторе StateAdapter мы получаем ресурс разметки и набор объектов и сохраняем их в отдельные переменные. Кроме того, для создания объекта View по полученному ресурсу разметки потребуется объект LayoutInflater, который также сохраняется в переменную.

В методе getView() устанавливается отображение элемента списка. Данный метод принимает три параметра:

- position: передает позицию элемента внутри адаптера, для которого создается представление;

- convertView: старое представление элемента, которое при наличии используется ListView в целях оптимизации;

- parent: родительский компонент для представления элемента.

В данном случае с помощью объекта LayoutInflater создаем объект View для каждого отдельного элемента в списке:

View view=inflater.inflate(this.layout, parent, false);

Из созданного объекта View получаем элементы ImageView и TextView по id:

ImageView flagView = (ImageView) view.findViewById(R.id.flag);

TextView nameView = (TextView) view.findViewById(R.id.name);

TextView capitalView = (TextView) view.findViewById(R.id.capital);

Это те элементы, которые определены в файле list_item.xml. Здесь же мы их получаем.

Далее используя параметр position, получаем объект State, для которого создается разметка:

State state = states.get(position);

Затем полученные элементы ImageView и TextView наполняем из полученного по позиции объекта State:

flagView.setImageResource(state.getFlagResource());

nameView.setText(state.getName());

capitalView.setText(state.getCapital());

И в конце созданный для отображения объекта State элемент View возвращается из метода:

return view;

Для использования изображений добавим в папку res/drawable несколько изображений, в моем случае это пять изображений флагов государств. В итоге проект будет выглядеть следующим образом, см. рис.8:



Рис. 8 – Состав проекта
В файле activity_main.xml определим ListView, в который будут загружаться данные:


android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal">

android:layout_height="match_parent"
android:layout_width="match_parent" />


/>
В файле MainActivity соединим StateAdapter с ListView:

package com.example.myapplication59;

import androidx.appcompat.app.AppCompatActivity;

import android.os.Bundle;

import android.view.View;
import android.widget.AdapterView;
import android.widget.ListView;
import android.widget.Toast;

import java.util.ArrayList;
import java.util.List;

public class MainActivity extends AppCompatActivity {

private List states = new ArrayList();

ListView countriesList;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);

// начальная инициализация списка
setInitialData();
// получаем элемент ListView
countriesList = (ListView) findViewById(R.id.countriesList);
// создаем адаптер
StateAdapter StateAdapter = new StateAdapter(this, R.layout.list_item, states);
// устанавливаем адаптер
countriesList.setAdapter( StateAdapter);
// слушатель выбора в списке
AdapterView.OnItemClickListener itemListener = new AdapterView.OnItemClickListener() {
@Override
public void onItemClick(AdapterView> parent, View v, int position, long id) {

// получаем выбранный пункт
State selectedState = (State)parent.getItemAtPosition(position);
Toast.makeText(getApplicationContext(), "Был выбран пункт " + selectedState.getName(),
Toast.LENGTH_SHORT).show();
}
};
countriesList.setOnItemClickListener(itemListener);
}
private void setInitialData(){

states.add(new State ("Бразилия", "Бразилиа", R.drawable.ccc));
states.add(new State ("Аргентина", "Буэнос-Айрес", R.drawable.ger));
states.add(new State ("Колумбия", "Богота", R.drawable.ppp));
states.add(new State ("Уругвай", "Монтевидео", R.drawable.slovak));
states.add(new State("Чили", "Сантьяго", R.drawable.usa));
}
}


В качестве источника данных здесь выступает класс ArrayList, который получает данные в методе setInitialData. Каждому добавляемому объекту State в списке передается название государства, его столица и ресурс изображения из папки res/drawable, который представляет флаг государства.

При создании адаптера ему передается ранее созданный ресурс разметки list_item.xml и список states, результат на вашем устройстве.
Задание:

  1. Изучите материал и проведите все мероприятия самостоятельно.

  2. Пример второго вопроса имеет ошибки-преднамеренные устраните их!