Evgenii Legotckoi
Evgenii LegotckoiШілде 21, 2015, 9:55 Т.Ж.

Android. Теңшеу тізім көрінісі

Кастомизация ListView является обычным явлением при разработке Приложения под ОС Android. ListView (Список) позволяет отображать однотипную информацию в Вашем Приложении, например показывать товары с ценами и характеристиками, если вы разрабатываете Приложение для онлайн продаж. При этом являясь по сути рутинной операцией, тем не менее, некоторые вопросы доставляют начинающим разработчикам массу неудобств. Некоторые из этих неудобств и вопросов будут разобраны в данной статье.

Структура проекта

В данном уроке предлагается создать небольшой список с флагами стран, названием валют этих стран и аббревиатурой этих стран.

Всего для создания списка используется четыре страны: Россия, Южная Африка, Сингапур, Турция. Флаги этих стран находятся в папке drawable. Также присутствует xml файл для создания бэкграунда ListViewи флагов. Для хранения названий и аббревиатур используется файл strings.xml. Также используется отдельный xml файл для создания разметки элемента ListView.

В Проекте присутствует три класса:

  1. MainActivity
  2. MyListAdapter - который отвечает за передачу данных в форму элемента списка
  3. DataFlags - класс, который призван облегчить передачу данных в Адаптер ListView

Формирование разметки элемента ListView

Для создания приятного глазу списка в данном уроке использовались следующие файлы:

  1. list_item.xml
  2. flag.xml
  3. listview_selector.xml
  4. styles.xml

listview.xml

В данном файле приводится разметка непосредственно элемента listview.

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="48dp"
    android:background="@drawable/listview_selector"
    android:orientation="horizontal">

    <ImageView
        android:id="@+id/flagImage"
        android:src="@drawable/flag_russian"
        android:layout_width="48dp"
        android:layout_height="40dp"
        android:layout_marginStart="16dp"
        android:layout_marginLeft="16dp"
        android:layout_marginRight="8dp"
        android:layout_marginEnd="8dp"
        android:contentDescription="@string/flag"
        android:background="@drawable/flag"
        android:layout_gravity="center_vertical"/>

    <TextView
        android:id="@+id/abbreviation"
        android:layout_width="52dp"
        android:layout_height="30dp"
        android:textColor="@color/black"
        android:textSize="24sp"
        android:text="@string/russianRUB"
        android:layout_marginRight="6dp"
        android:layout_marginEnd="6dp"
        android:layout_gravity="center_vertical"/>

    <TextView
        android:id="@+id/name"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:textColor="@color/black"
        android:textSize="14sp"
        android:text="@string/russian"
        android:gravity="center"
        android:layout_gravity="center"
        android:singleLine="false"/>

</LinearLayout>

flag.xml

В данном файле создан backgroud для ImageView, в котором будет отображаться флаг. Края подложки для флага скруглены. А также настроен цвет подложки.

<?xml version="1.0" encoding="UTF-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android">

    <solid android:color="@color/blue_grey_100" />

    <padding
        android:bottom="2dp"
        android:top="2dp"
        android:right="2dp"
        android:left="2dp"/>

    <corners android:radius="4dp"/>

</shape>

listview_selector.xml

Данная разметка используется как background для элемента ListView. В данном файле настраивается цвет фона элемента в нормальном режиме и при нажатии на элемент списка.

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

    <item
        android:state_pressed="true"
        android:drawable="@color/blue_grey_100" />

    <item
        android:state_selected="true"
        android:state_pressed="false"
        android:drawable="@color/blue_grey_100" />

</selector>

styles.xml

Файл стилей знаком всем, кто занимается разработкой под Android. В данном случае он используется только лишь для хранения кодов цветов, используемых в данном примере.

<resources>

    <!-- Base application theme. -->
    <style name="AppTheme" parent="Theme.AppCompat.Light.DarkActionBar">
    </style>

    <color name="white">#ffffff</color>
    <color name="black">#000000</color>
    <color name="blue_grey_100">#CFD8DC</color>

</resources>

activity_main.xml

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

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:background="@color/white"
    android:paddingLeft="@dimen/activity_horizontal_margin"
    android:paddingRight="@dimen/activity_horizontal_margin"
    android:paddingTop="@dimen/activity_vertical_margin"
    android:paddingBottom="@dimen/activity_vertical_margin" tools:context=".MainActivity">

    <ListView
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:id="@+id/listViews" />

</RelativeLayout>

Основной класс проекта - MainActivity.java

В Данном классе производится запуск основной активити проекта, в которой будет отображаться кастомный ListView. Данные в ListView передаются с помощью списка ArrayList, в который помечаются объекты данных для каждого элемента. Группировка данных для элемента ListView производится с помощью отдельного класса, формирующего структуру данных, в которой будут храниться ID изображения флага, ID строки названия валюты страны, а также ID строки Аббревиатур валют стран.

По сути в этом классе производится стандартная настройка ListView с тем отличием, что используется не обычный List, а ArrayList, в который передается объект, а не единичная строка.

package ru.evileg.listview;

import android.os.Bundle;
import android.support.v7.app.ActionBarActivity;
import android.view.Menu;
import android.view.MenuItem;
import android.widget.ListView;

import java.util.ArrayList;


public class MainActivity extends ActionBarActivity {

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

        // Находим ListView в разметке активити
        ListView listView = (ListView) this.findViewById(R.id.listViews);

        // Создаём ListView, в котором будут храниться данные для списка
        ArrayList<DataFlags> list = new ArrayList<>();
        list.clear();

        /* Наполняем List данным. В данном случае данные передаются Объектом,
         * в котором хранятся id, указывающие на флаги в ресурсах, а также
         * на Строки, в которых прописаны названия валют стран и аббревиатуры этих валют */
        list.add(new DataFlags(R.drawable.flag_russian, R.string.russian, R.string.russianRUB));
        list.add(new DataFlags(R.drawable.flag_africa, R.string.africa, R.string.africaZAR));
        list.add(new DataFlags(R.drawable.flag_singapore, R.string.singapore, R.string.singaporeSGD));
        list.add(new DataFlags(R.drawable.flag_turkish, R.string.turkish, R.string.turkishTRY));

        /* Создаём адаптер, который будет передавать данные из List`а в
         * элемент ListView и подключаем его непосредственно к ListView`у
         */
        MyListAdapter myListAdaptery = new MyListAdapter(this, list);
        listView.setAdapter(myListAdaptery);
    }

    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        // Inflate the menu; this adds items to the action bar if it is present.
        getMenuInflater().inflate(R.menu.menu_main, menu);
        return true;
    }

    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
        // Handle action bar item clicks here. The action bar will
        // automatically handle clicks on the Home/Up button, so long
        // as you specify a parent activity in AndroidManifest.xml.
        int id = item.getItemId();

        //noinspection SimplifiableIfStatement
        if (id == R.id.action_settings) {
            return true;
        }

        return super.onOptionsItemSelected(item);
    }
}

Все строки, которые применяются для ListView хранятся непосредственно в файле ресурсов strings.xml

<resources>
    <string name="app_name">ListView</string>
    <string name="action_settings">Settings</string>

    <string name="africaZAR">ZAR</string>
    <string name="russianRUB">RUB</string>
    <string name="singaporeSGD">SGD</string>
    <string name="turkishTRY">TRY</string>

    <string name="africa">South African\nrand</string>
    <string name="russian">Russian\nrouble</string>
    <string name="singapore">Singapore\ndollar</string>
    <string name="turkish">Turkish\nlira</string>

    <string name="flag">flag</string>
</resources>

Класс DataFlags.java

Данный класс служит для формирования объекта, в котором хранятся данные для элементов ListView. Каждый объект обслуживает один из элементов ListView в данном проекте. Класс представляет собой общность переменных, и набор get методов для получения данных из объекта, формируемого данным классом.

package ru.evileg.listview;

/**
 * Application ListView
 * Created by EvILeg on 21.07.2015.
 */
public class DataFlags {

    private int flagID;
    private int nameID;
    private int abbreviationID;

    public DataFlags (int _flagID, int _nameID, int _abbreviationID){
        flagID = _flagID;
        nameID = _nameID;
        abbreviationID = _abbreviationID;
    }

    public int getFlagID(){
        return flagID;
    }

    public int getNameID(){
        return nameID;
    }

    public int getAbbreviationID() {
        return abbreviationID;
    }
}

Класс MyListAdapter

Самый важный класс в данном уроке. Именно этот класс служит для передачи данных из ArrayList в ListView. Данный класс расширяет возможности родительского класса BaseAdapter.

package ru.evileg.listview;

import android.content.Context;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
import android.widget.ImageView;
import android.widget.TextView;

import java.util.ArrayList;

/**
 * Application ListView
 * Created by EvILeg on 21.07.2015.
 */
public class MyListAdapter extends BaseAdapter {

    /*
     * Создаем объекты для отображения внешнего вида элемента
     * и объекта списка, с которым будет производиться работа
     */
    private LayoutInflater LInflater;
    private ArrayList<DataFlags> list;

    /*
     * Конструктор класса. В данном случае лишь транслируется лист с данными
     * в лист адаптера, с которым будет производиться непосредственная работа
     */
    public MyListAdapter(Context context, ArrayList<DataFlags> data){

        list = data;
        LInflater = (LayoutInflater) context
                .getSystemService(Context.LAYOUT_INFLATER_SERVICE);
    }

    /*
     * Далее идут стандартные методы родительского класса BaseAdapter.
     * Внимательно ознакомьтесь с отличиями методов в уроке и методов,
     * которые автоматически создает Android Studio.
     * Данные методы должны работать непосредственно с используемым нами ArrayList
     * и структурой данных, формируемой классом DataFlags
     */
    @Override
    public int getCount() {
        return list.size();
    }

    @Override
    public DataFlags getItem(int position) {
        return list.get(position);
    }

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

    /*
     * Метод, в котором формируется внешний вид элементов с его наполнением
     */
    @Override
    public View getView(int position, View convertView, ViewGroup parent) {

        ViewHolder holder;
        View v = convertView;

        /*
         * В том случае, если вид элемента не создан, производится его создание
         * с помощью ViewHolder и тегирование данного элемента конкретным holder объектом
         */
        if ( v == null){
            holder = new ViewHolder();
            v = LInflater.inflate(R.layout.list_item, parent, false);
            holder.flag = (ImageView) v.findViewById(R.id.flagImage);
            holder.name = (TextView) v.findViewById(R.id.name);
            holder.abbreviation = ((TextView) v.findViewById(R.id.abbreviation));
            v.setTag(holder);
        }

        /*
         * После того, как все элементы определены, производится соотнесение
         * внешнего вида, данных и конкретной позиции в ListView.
         * После чего из ArrayList забираются данные для элемента ListView и
         * передаются во внешний вид элемента
         */
        holder = (ViewHolder) v.getTag();
        DataFlags dataFlags = getData(position);

        holder.flag.setImageResource(dataFlags.getFlagID());
        holder.name.setText(v.getResources().getString(dataFlags.getNameID()));
        holder.abbreviation.setText(v.getResources().getString(dataFlags.getAbbreviationID()));

        return v;
    }

    /*
     * Метод, который забирает объект из ArrayList для дальнейшей работы с ним
     * и передачи его данных в элемент ListView
     */
    DataFlags getData(int position){
        return (getItem(position));
    }

    /*
     * Данная структура данных необходима для того, чтобы при пролистывании
     * большого списка не возникало артефактов и перескакивания данных с одной позиции ListView
     * на другую, что достигается тегированием каждого элемента ListView
     */
    private static class ViewHolder {
        private ImageView flag;
        private TextView name;
        private TextView abbreviation;
    }
}

Использование ViewHolder принципиально важно, поскольку, если не применять данный прием, можно получить неадекватной поведение ListView, при котором будет происходит неконтролируемое перескакивание данных с одной позиции ListView на другую. Причем это будет происходит только внешне, а на самом деле данные будут оставаться на своих местах. Будет возникать несоответствие внешнего вида ListView с его содержанием.

Итог

Если в процессе изучения урока не возникло никаких проблем и ошибок, то внешний вид полученного ListView должен быть подобен следующему:

Кастомный ListView

Кастомный ListView с нажатым элементом

Рекомендуем хостинг TIMEWEB
Рекомендуем хостинг TIMEWEB
Стабильный хостинг, на котором располагается социальная сеть EVILEG. Для проектов на Django рекомендуем VDS хостинг.

Ол саған ұнайды ма? Әлеуметтік желілерде бөлісіңіз!

ДВ
  • Наурыз 9, 2019, 6:53 Т.Ж.
  • (өңделген)

Спасибо за пример.
У меня возникает ошибка.

AndroidRuntime: FATAL EXCEPTION: main
Подскажите, пожалуйста, с чем это может быть связано?

Evgenii Legotckoi
  • Наурыз 11, 2019, 4:32 Т.Ж.

Честно, вот в этой ошибке может быть что угодно, вплоть до того, что вы просто где-то не в том порядке код запсали.

AndroidRuntime: FATAL EXCEPTION: main

Это просто ошибка в рантайме, для всего, что могло случиться.

Пікірлер

Тек рұқсаты бар пайдаланушылар ғана пікір қалдыра алады.
Кіріңіз немесе Тіркеліңіз
AD

C++ - Тест 004. Указатели, Массивы и Циклы

  • Нәтиже:50ұпай,
  • Бағалау ұпайлары-4
m
  • molni99
  • Қаз. 26, 2024, 1:37 Т.Ж.

C++ - Тест 004. Указатели, Массивы и Циклы

  • Нәтиже:80ұпай,
  • Бағалау ұпайлары4
m
  • molni99
  • Қаз. 26, 2024, 1:29 Т.Ж.

C++ - Тест 004. Указатели, Массивы и Циклы

  • Нәтиже:20ұпай,
  • Бағалау ұпайлары-10
Соңғы пікірлер
ИМ
Игорь МаксимовҚар. 22, 2024, 11:51 Т.Ж.
Django - Оқулық 017. Теңшелген Django кіру беті Добрый вечер Евгений! Я сделал себе авторизацию аналогичную вашей, все работает, кроме возврата к предидущей странице. Редеректит всегда на главную, хотя в логах сервера вижу запросы на правильн…
Evgenii Legotckoi
Evgenii LegotckoiҚаз. 31, 2024, 2:37 Т.Қ.
Django - Сабақ 064. Python Markdown кеңейтімін қалай жазуға болады Добрый день. Да, можно. Либо через такие же плагины, либо с постобработкой через python библиотеку Beautiful Soup
A
ALO1ZEҚаз. 19, 2024, 8:19 Т.Ж.
Qt Creator көмегімен fb3 файл оқу құралы Подскажите как это запустить? Я не шарю в программировании и кодинге. Скачал и установаил Qt, но куча ошибок выдается и не запустить. А очень надо fb3 переконвертировать в html
ИМ
Игорь МаксимовҚаз. 5, 2024, 7:51 Т.Ж.
Django - Сабақ 064. Python Markdown кеңейтімін қалай жазуға болады Приветствую Евгений! У меня вопрос. Можно ли вставлять свои классы в разметку редактора markdown? Допустим имея стандартную разметку: <ul> <li></li> <li></l…
d
dblas5Шілде 5, 2024, 11:02 Т.Ж.
QML - Сабақ 016. SQLite деректер қоры және онымен QML Qt-та жұмыс істеу Здравствуйте, возникает такая проблема (я новичок): ApplicationWindow неизвестный элемент. (М300) для TextField и Button аналогично. Могу предположить, что из-за более новой верси…
Енді форумда талқылаңыз
m
moogoҚар. 22, 2024, 7:17 Т.Ж.
Mosquito Spray System Effective Mosquito Systems for Backyard | Eco-Friendly Misting Control Device & Repellent Spray - Moogo ; Upgrade your backyard with our mosquito-repellent device! Our misters conce…
Evgenii Legotckoi
Evgenii LegotckoiМаусым 24, 2024, 3:11 Т.Қ.
добавить qlineseries в функции Я тут. Работы оень много. Отправил его в бан.
t
tonypeachey1Қар. 15, 2024, 6:04 Т.Ж.
google domain [url=https://google.com/]domain[/url] domain [http://www.example.com link title]
NSProject
NSProjectМаусым 4, 2022, 3:49 Т.Ж.
Всё ещё разбираюсь с кешем. В следствии прочтения данной статьи. Я принял для себя решение сделать кеширование свойств менеджера модели LikeDislike. И так как установка evileg_core для меня не была возможна, ибо он писался…

Бізді әлеуметтік желілерде бақылаңыз