четверг, 9 сентября 2010 г.

Создание списков. Использование ListActivity

Введение
ListViews используются для создания вьюверов со списками данных в Android приложений. Списки могут заполняется данными из источников Android’a с курсорами или же простыми массивами. Пользовательские вьеверы наследованные от списка, могут содержать дополнительное форматирование, в том числе чекбоксы с флажками и иконки. Создадим новый проект под названием TestListActivities. 


Основы применения ListActivity
Layout
Чтобы создать видимый список с элементами, он должен существовать в layout. Возможны два случая один – данные есть, список полный и второй – данные отсутствуют, список пустой. Для первого случая объявим узел ListView с идентификатором (android:id) @android:id/list", он будет отображать данные. Для второго случая объявим TextView с идентификатором “@android:id/empty".  Разметка layout’a, для простоты используем LinearLayout:

 
     android:orientation="vertical"
     android:layout_width="fill_parent"
     android:layout_height="fill_parent"
     >
     
         android:id="@android:id/list"
         android:layout_width="fill_parent" 
         android:layout_height="wrap_content" 
         />
     
         android:layout_width="wrap_content"
         android:layout_height="wrap_content"
         android:text="Empty set"
         />
 

JAVA код
package com.higherpass.android.widgets.test;
 
 import android.app.ListActivity;
 import android.os.Bundle;
 import android.widget.ArrayAdapter;
 
 public class TestListActivities extends ListActivity {
         String[] listItems = {"exploring", "android", 
                               "list", "activities"};
     /** Called when the activity is first created. */
     @Override
     public void onCreate(Bundle savedInstanceState) {
         super.onCreate(savedInstanceState);
         setContentView(R.layout.main);
         setListAdapter(new ArrayAdapter(this, 
              android.R.layout.simple_list_item_1, listItems));
     }
 }

Вместо наследования от класса Activity, мы наследуем наш главный класс от ListActivity.
ListItems,- массив строк, содержащий текст, который будет заполнять список.
Как и в других видах Activity, ListActivity использует метод OnCreate(), и первое, что нужно сделать это вызвать его в базовом классе super.onCreate. Следующий шаг, это обращение к файлу main.xml с разметкой интерфейса с помощью setContentView(R.layout.main).

Последнее, что нужно сделать, это заполнить список. Для заполнения списка нужно создать ArrayAdapter и передать его в метод setListAdapter(). ArrayAdapters управляет объектами ListView на основе подложенного под него массива. Конструктор ArrayAdapter имеет 3 параметра:
  • текущий экземпляр класса (this);
  • layout, используемый для каждого элемента списка; 
  • массив самих элементов.
Android имеет несколько встроенных layout'ов, которые доступны в android.R.layout. Тут мы использовали android.R.layout.simple_list_item_1, который отображает одну строку.

Прикрепление курсора(Cursor)
Класс CursorAdapter позволяет использовать стандартные курсоры Android, которые используются для наполнения ListView. Это обеспечивает простой интерфейс для базы данных в Андроиде.
См. Android курсор учебник для получения дополнительной информации о курсорах.
ListAdapter с готовыми курсорами называется BasicCursorAdapter. Чтобы продемонстрировать использование курсоров со списками мы будем запрашивать закладки браузера. В этом примере мы должны предоставить доступ к закладки в файле AndroidManifest.xml, добавив следующие строки:

 


Это разрешения для нашего приложения на чтение и запись закладок браузера.
package com.higherpass.android.widgets.test;

import android.app.ListActivity;
import android.database.Cursor;
import android.media.MediaPlayer;
import android.os.Bundle;
import android.provider.Browser;
import android.provider.Settings;

import android.provider.MediaStore.Audio.Media;
import android.widget.SimpleCursorAdapter;

public class TestListActivities extends ListActivity {
    
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);
        String[] projection = new String[] {Browser.BookmarkColumns._ID, 
                                     Browser.BookmarkColumns.TITLE, 
                                     Browser.BookmarkColumns.URL};
        String[] displayFields = new String[] {Browser.BookmarkColumns.TITLE, 
                                     Browser.BookmarkColumns.URL};
        int[] displayViews = new int[] { android.R.id.text1, 
                                     android.R.id.text2 };

        Cursor cur = managedQuery(android.provider.Browser.BOOKMARKS_URI, 
                       projection, null, null, null);
        setListAdapter(new SimpleCursorAdapter(this, 
                       android.R.layout.simple_list_item_2, cur, 
                       displayFields, displayViews));
   }
}

Использование простых списков с курсорами очень похоже на использование массивов. Кое-что необходимо сделать для начала: создать массив строк-констант,- называний для столбцов базы данных, которые мы хотим получить. Следующих шаг,- создание массива строк displayFields, содержащего поля, которые будут отображаться во вьевере. DisplayFields связан с массивом displayColumns, для перемещения данных из текущего места БД установленного курсором в соответствующие места вьевера. Порядок массивов displayFields и displayColumns имеют важное значение. Данные из массива перемещаются в элементы вьевера, в жестком соответствии. В нашем случае, название закладки переходит в поле text1, а URL переходит в поле text2.
Следующий шаг,- создание курсора. Для простоты мы просто будем проходить по URI в базе данных и вытаскивать данные через managedQuery.
См. статьи о курсорах для получения дополнительной информации о курсорах.
Наконец, создадим SimpleCursorAdapter. Как и в ArrayAdapter первый параметр является текущий экземпляр класса (this). Вследующий параметр, автоматически генерированная в классе R переменная, которая соответствует вьеверу для строки списка. В этом примере мы использовали android.R.layout.simple_list_item_2. Это небольшое упрощение, для перехода к более сложному,- настройки отображения элементов списка. Android.R.layout.simple_list_item_2 layout встроен в Android SDK. Он имеет 2-ва внутренних TextViews, один с большим шрифтом и другой с меньшими шрифтом, расположенным ниже. Третий параметр конструктора SimpleCursorAdapter является сам курсор. Четвертый параметр,- массив строк displayFields и, наконец, последний,- displayViews.

Пользовательские элементы для строк списка

Как вы только что видели на примере списка элементов, списки могут быть произвольно настроены. Некоторые общие настройки могут форматировать отображаемый текст, добавив, например, иконки и флажки в чекбоксах. Чтобы настроить текстовый layout, мы просто создадим новый layout с пользовательскими иконками и флажками.

Форматирование текста и его организация
Щелкните правой кнопкой мыши на res/layouts/ и  выберите New > android XML file. Установите имя файла text_list.xml, выберите корневой элемент LinearLayout и нажмите кнопку "Готово".


    xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    android:orientation="vertical"
    >
    
        xmlns:android="http://schemas.android.com/apk/res/android"
        android:layout_width="fill_parent"
        android:layout_height="fill_parent"*** 
        android:orientation="horizontal"
        >
        
            android:id="@+id/bmark_visits"
            android:layout_width="wrap_content" 
            android:layout_height="wrap_content"
            />
        
            android:id="@+id/bmark_title"
            android:layout_width="wrap_content" 
            android:layout_height="wrap_content"
            />
    
    
        android:id="@+id/bmark_url"
        android:layout_width="fill_parent" 
        android:layout_height="wrap_content"
        />

Эта разметка LinearLayout создает основу для создания списка, который будет отображает информацию о закладках. Внешний LinearLayout имеет ориентацию,- вертикально и содержит вложенные элементы:
LinearLayout, расположенный горизонтально, содержащий текстовые поля для числа посещений и названия ресурса, текстовое поле для самого URL. Теперь вернемся назад в код и изменим TestListActivities.java:

package com.higherpass.android.widgets.test;

import android.app.ListActivity;
import android.database.Cursor;
import android.os.Bundle;
import android.provider.Browser;
import android.widget.SimpleCursorAdapter;

public class TestListActivities extends ListActivity {
    String[] listItems = {"exploring", "android", "list", "activities"};

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);
        String[] projection = new String[] {Browser.BookmarkColumns._ID, 
                                    Browser.BookmarkColumns.TITLE, 
                                    Browser.BookmarkColumns.URL,
                                    Browser.BookmarkColumns.VISITS};
        String[] displayFields = new String[] {Browser.BookmarkColumns.VISITS,
                                    Browser.BookmarkColumns.TITLE, 
                                    Browser.BookmarkColumns.URL};
        int[] displayViews = new int[] { R.id.bmark_visits,
                                    R.id.bmark_title,
                                    R.id.bmark_url};

        Cursor cur = managedQuery(android.provider.Browser.BOOKMARKS_URI, 
                       projection, null, null, null);

        setListAdapter(new SimpleCursorAdapter(this, 
                        R.layout.text_list, cur, 
                        displayFields, displayViews
        ));
    }
}

Есть несколько ключевых изменений, которые мы сделаем в предведущий код. Сначала добавим Browser.BookmarkColumns.VISITS для проекции полейи корректируем массивы строк displayFields и displayViews,как показано в коде. Эти изменения установят SimpleCursorAdapter для режима отображения данных в новом формате. Затем укажем тот layout, описаный выше в SimpleCursorAdapter(R.layout.text_list). Сейчас в списке будут отображаться элементы с измененым внешнем видом.

Добавление иконок в список

Картинки и другие графические элементы  так же могут быть добавлены в элементы списока. Нам необходимо расширить SimpleCursorAdapter, переопределить метод GetView. Сначала, создадим новый XML-файл в res/layouts/, имеющий называние image_list.xml с корневым элементом LinearLayout.


  xmlns:android="http://schemas.android.com/apk/res/android"
  android:layout_width="fill_parent"
  android:layout_height="wrap_content"
  android:orientation="horizontal">
  
  
     android:id="@+id/bimage"
     android:layout_height="22px"
     android:layout_width="22px"
     android:src="@drawable/icon"
     />
  
     android:id="@+id/btitle"
     android:layout_width="fill_parent"
     android:layout_height="wrap_content"/>

Это простой линейный layout, который будет использоваться для отображения каждого элемента в списке. Элемент ImageView будет использоваться для отображения иконки закладки, если он хранится, Если иконки нет, будет отображена икона приложения по умолчанию. В коде ниже мы преобразуем изображение в иконку, если оно есть. Компонент TextView будет использоваться для отображения названия закладкок.
Теперь нам нужно расширить SimpleCursorAdapter. Создайте новый класс, называемый ImageCursorAdapter в том же пакете исходного кода, что и TestListActivities.java. Новый класс должен расширять android.widget.SimpleCursorAdapter.

package com.higherpass.android.widgets.test;

import android.content.Context;
import android.database.Cursor;
import android.graphics.BitmapFactory;
import android.provider.Browser;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageView;
import android.widget.SimpleCursorAdapter;
import android.widget.TextView;

public class ImageCursorAdapter extends SimpleCursorAdapter {

        private Cursor c;
        private Context context;

    public ImageCursorAdapter(Context context, int layout, Cursor c,
            String[] from, int[] to) {
        super(context, layout, c, from, to);
        this.c = c;
        this.context = context;
    }

    public View getView(int pos, View inView, ViewGroup parent) {
           View v = inView;
           if (v == null) {
                LayoutInflater inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
                v = inflater.inflate(R.layout.image_list, null);
           }
           this.c.moveToPosition(pos);        
           String bookmark = this.c.getString(this.c.getColumnIndex(Browser.BookmarkColumns.TITLE));
           byte[] favicon = this.c.getBlob(this.c.getColumnIndex(Browser.BookmarkColumns.FAVICON));
           if (favicon != null) {
           ImageView iv = (ImageView) v.findViewById(R.id.bimage);
               iv.setImageBitmap(BitmapFactory.decodeByteArray(favicon, 0, favicon.length));
           }
               TextView bTitle = (TextView) v.findViewById(R.id.btitle);
               bTitle.setText(bookmark);
           return(v);
    }

}

ImageCursorAdapter класс расширяет класс SimpleCursorAdapter так, что мы можем переопределить метод GetView(). Это позволит нам настроить строки в ListView. Во-первых нам надо создать конструктор. Конструктор, public ImageCursorAdapter() имеет 5 параметров:

  • context,
  • используемый layout,
  • курсор для данных,
  • поле для просмотра элементов массивов которые отображаются.
Курсор будет передаваться с другими параметрами конструктору для SimpleCursorAdapter через вызов метода суперкласса(super()).
Теперь переопределим метод GetView() из SimpleCursorAdapter. Метод GetView() принимает 3 параметра, положение в списке/курсор, вьевер и родитель. Если вьевер не существует, метод GetView(), используя LayoutInflater, создает его на основе разметки layout. Следующий шаг,- перемещение курсора в текущее положение. Для получения дополнительной информации об использовании курсоров см. использование курсоров в онлайн-справке по Android.
Далее идет получение названия закладки и сохранение его в строке bookmark. Значок хранится как байтовый массив в базе данных SQLite. Функция курсора getBlob() правильно извлекает данные и возвращает её в виде массива байтов. Это хорошо, потому что мы можем использовать массив байтов, чтобы создать bitmap для картинке. Если значок есть, то иконка хранится в базе данных. Затем означим из компонентов вьевера ImageView. Теперь, используя BitmapFactory, создим bitmap из массива байтов и установим его в качестве изображения ImageView с помощью метода setImageBitmap. Для получения дополнительной информации см. справку по изображениям Android. Наконец установим TextView и возвратим вьевер.

Использование флажков в чекбоксах

Создание списка с флажками похож на создание списка с изображениями. Необходимо создать свой layout и расширить класс SimpleCursorAdapter, чтобы переопределить метод GetView(). Создадим новый XML-файл в res/layout/ с называнием check_list.xml. Он будет использоваться в layout в списке с чекбоксами.


    xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="fill_parent"
    android:layout_height="wrap_content"
    android:orientation="horizontal">
  
       android:id="@+id/bcheck"
       android:layout_height="wrap_content"
       android:layout_width="wrap_content"
       />

Это простой LinearLayout с единственным компонентом CheckBox, имеющим идентификатор bcheck. Чекбоксы состоят из флажка и компонента TextView с правой стороны.
Создадим новый класс в проекте под названием CheckboxCursorAdapter, который расширяет android.widget.SimpleCursorAdapter.

package com.higherpass.android.widgets.test; 

import java.util.ArrayList; 

import android.content.Context;
import android.database.Cursor;
import android.provider.Browser;
import android.view.LayoutInflater;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.ViewGroup;
import android.widget.CheckBox;
import android.widget.SimpleCursorAdapter;
import android.widget.TextView;

public class CheckboxCursorAdapter extends SimpleCursorAdapter {

    private Cursor c;
    private Context context;
    private ArrayList checkList = new ArrayList();
    
    public CheckboxCursorAdapter(Context context, int layout, Cursor c,
            String[] from, int[] to) {
        super(context, layout, c, from, to);
        this.c = c;
            this.context = context;
    }
    
    public View getView(int pos, View inView, ViewGroup parent) {
        View v = inView;
        if (v == null) {
            LayoutInflater inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
            v = inflater.inflate(R.layout.check_list, null);
        }
                this.c.moveToPosition(pos);        
        String bookmark = this.c.getString(this.c.getColumnIndex(Browser.BookmarkColumns.TITLE));
        CheckBox cBox = (CheckBox) v.findViewById(R.id.bcheck);
        cBox.setTag(Integer.parseInt(this.c.getString(this.c.getColumnIndex(Browser.BookmarkColumns._ID))));
        cBox.setText(bookmark);
        if (Integer.parseInt(this.c.getString(this.c.getColumnIndex(Browser.BookmarkColumns._ID))) % 2 != 0) {
            cBox.setChecked(true);    
        }
        return(v);
    }

}

Класс CheckboxCursorAdapter имеет простой конструктор, такой как и ImageCursorAdapter. Конструктор должен просто передавать данные в конструктор SimpleCursorAdapter, а метод GetView() очень похож на описанный ранее. Если вьевера нет, нам нужно, используя LayoutInflater создать вьеверна основе разметки в check_list.xml. Затем переместить курсор в нужное положение в списке, и заполнить данные в правильной последовательности вьевера.

Используйте метод cBox.setText() для означивание текста чекбокса. Для установки галочек используйте метод setChecked(). В этом примере, чекбоксы по умолчанию с галочками, для всех элементов с нечетным идентификаторами БД в списке.

Так же необходимо провести некоторые изменения в коде, чтобы TestListActivities отображало список с чекбоксами.

public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);
        String[] projection = new String[] {Browser.BookmarkColumns._ID, 
                                    Browser.BookmarkColumns.TITLE};
        String[] displayFields = new String[] {Browser.BookmarkColumns.TITLE};
        int[] displayViews = new int[] {R.id.btitle};
 
        Cursor cur = managedQuery(android.provider.Browser.BOOKMARKS_URI, 
                       projection, null, null, null);
 
        setListAdapter(new CheckboxCursorAdapter(this, 
                R.layout.check_list, cur, 
            displayFields, displayViews
        ));
    }

Добавление обработки событий

Для демонстрации обработки, добавим возможность управлять элементами списка в CheckboxCursorAdapter. Действия обрабатываются слушателями, мы будем использовать onClickListener. OnClickListener должен быть прикреплен к чекбоксу в методе GetView(). Все что нужно для этого, создавать метод onClickListener(), для управления списком, а также установить позицию в списке в поле чекбокса.
Список использует уникальный идентификатор для каждого своего элемента, который мы можем хранить в ArrayList, для управления галочками. Для этого мы для текущей позиции в списке в чекбоксе вызовим метод setTag(). В методе GetView() создаются и прикрепляются onClickListener () для каждого чекбокса, СВох. OnClickListener() ожидает класс, который содержит public void method onClick(). OnClickListener () будет вызывать его для выбранного элемента. Функция OnClick() должна получить значение поле тега(есть ли галочка) с помощью метода getTag (). Если галки нет, то произойдет добавление в ArrayList и галка установиться. Если галка, есть, она снимиться и удалиться из ArrayList.

package com.higherpass.android.widgets.test;

import java.util.ArrayList; 

import android.content.Context;
import android.database.Cursor;
import android.provider.Browser;
import android.view.LayoutInflater;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.ViewGroup;
import android.widget.CheckBox;
import android.widget.SimpleCursorAdapter;
import android.widget.TextView;

public class CheckboxCursorAdapter extends SimpleCursorAdapter {

    private Cursor c;
    private Context context;
    private ArrayList checkList = new ArrayList();
    
    public CheckboxCursorAdapter(Context context, int layout, Cursor c,
            String[] from, int[] to) {
        super(context, layout, c, from, to);
        this.c = c;
        this.context = context;
    }
    
    public View getView(int pos, View inView, ViewGroup parent) {
        View v = inView;
        if (v == null) {
            LayoutInflater inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
            v = inflater.inflate(R.layout.check_list, null);
        }
        this.c.moveToPosition(pos);        
        String bookmark = this.c.getString(this.c.getColumnIndex(Browser.BookmarkColumns.TITLE));
        CheckBox cBox = (CheckBox) v.findViewById(R.id.bcheck);
        cBox.setTag(pos);
        cBox.setText(bookmark);
        if (Integer.parseInt(this.c.getString(this.c.getColumnIndex(Browser.BookmarkColumns._ID))) % 2 != 0) {
            cBox.setChecked(true);    
            checkList.add((String) cBox.getTag());
        }
        cBox.setOnClickListener(new OnClickListener() {  
            @Override
            public void onClick(View v) {
                CheckBox cBox = (CheckBox) v.findViewById(R.id.bcheck);
                if (cBox.isChecked()) {
                    //cBox.setChecked(false);
                    checkList.add((String) cBox.getTag());
                } 
                else if (!cBox.isChecked()) {
                    //cBox.setChecked(true);
                    checkList.remove(cBox.getTag());
                }
            }
        });

        return(v);
    }

}

Никаких других изменений не требуется, помимо добавления к CheckboxCursorAdapter onClickListener. 
Этого вполне достаточно, для начала использования списков в приложениях для Android'а.

Комментариев нет:

Отправить комментарий