Показаны сообщения с ярлыком ListView. Показать все сообщения
Показаны сообщения с ярлыком ListView. Показать все сообщения

понедельник, 6 июня 2011 г.

Android: список с элементами произвольного вида

Что такое "классический интерфейс Android"? Однажды мы с нашим дизайнером искали ответ на этот вопрос. Ответ нашёлся просто. Открываем самое что ни на есть стандартное приложение - "Настройки" и что мы там наблюдаем?



Списки. ListView. Только выглядят они очень по-разному. И если мы решили сделать в своём приложении всё "классически", то нужно уметь поставить элементом списка любой набор View, который требуется в данном контексте логикой нашего приложения.
Делаем это в три этапа.

1. XML-layout элемента
В каталоге res/layout нашего проекта создаём xml-файл с разметкой элемента списка.
Например такая разметка:
<?xml version="1.0" encoding="UTF-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
  android:layout_width="fill_parent"
  android:layout_height="wrap_content"
  android:gravity="center_vertical"
  android:orientation="horizontal">
  <ImageView
    android:id="@+id/contact_item_icon"
    android:layout_width="50sp"
    android:layout_height="50sp"
    android:padding="5sp"/>
  <LinearLayout
    android:layout_width="fill_parent"
    android:layout_height="wrap_content"
    android:gravity="center_vertical"
    android:orientation="vertical">
    <TextView
      android:id="@+id/contact_item_title"
      android:layout_width="wrap_content"
      android:layout_height="wrap_content"
      android:textSize="16sp"
      android:textStyle="bold"/>
    <TextView
      android:id="@+id/contact_item_details"
      android:layout_width="wrap_content"
      android:layout_height="wrap_content"
      android:textSize="10sp"/>
  </LinearLayout>
</LinearLayout>
выведет такой список:







2. Создание ListAdapter-a
Это, пожалуй, наиболее неочевидная часть процесса. ListView для построения списка нуждается не только в данных и разметке. Для корректного наложения первого на второе нужен класс, расширяющий ArrayAdapter. Вот как он выглядит в нашем случае:
public class ContactListAdapter extends ArrayAdapter {

  private Contact[] conts;
  private Context context;

  public ContactListAdapter(Context context, int textViewResourceId, Object[] conts) {
    super(context, textViewResourceId, conts);
    this.conts = (Contact[]) conts;
    this.context = context;
  }

  @Override
  public View getView(int position, View convertView, ViewGroup parent) {
    View v = convertView;
    if (v == null) {
      LayoutInflater inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
      v = inflater.inflate(R.layout.image_list_item, null);
    }
    TextView bTitle = (TextView) v.findViewById(R.id.contact_item_title);
    TextView bDetails = (TextView) v.findViewById(R.id.contact_item_details);
    ImageView iView = (ImageView) v.findViewById(R.id.contact_item_icon);
    Contact c = conts[position];
    bTitle.setText(c.getDisplayName());
    if (c.getIcon()!=null) {
      iView.setImageBitmap(c.getIcon());
    } else {
      iView.setImageResource(android.R.drawable.ic_menu_gallery);
    }
    if(c.getPhone().size()>0) {
      bDetails.setText(c.getPhone().get(0).getNumber());
    } else if(c.getEmail().size()>0) {
      bDetails.setText(c.getEmail().get(0).getAddress());
    } else if(c.getImAddresses().size()>0) {
      bDetails.setText(c.getImAddresses().get(0).getName());
    }
    return v;
  }
}

Конструктор принимает ссылку на ресурс xml, в котором описана разметка элемента списка а также массив объектов, которые должны быть представлены в виде списка. В данном случае - это контакты из списка нашего телефона. Переопределённый метод getView связывает поля нашего класса с объектами из разметки.

3. Ну, и, собственно, вызов...
ListView lw = (ListView) findViewById(R.id.contacts_list);
lw.setAdapter(new ContactListAdapter(this, R.layout.image_list_item, items));

Тут items - наш массив контактов.

среда, 11 мая 2011 г.

Android: список операций для элемента списка

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

Принцип работы списка будет таким:

  1. Создаём ListView и на событие OnItemClick вешаем слушатель (назовём его, к примеру Operation).
  2. В методе обработчике слушателя строим диалоговое окно со списком операций. Список операций в виде String[] и заголовок окна передаём в Operation при вызове конструктора слушателя. 
  3. На событие клика по названию операции в диалоговом окне вешаем этот же слушатель. Для этого наш класс Operation должен реализовывать не только интерфейс OnItemClickListener но и DialogInterface.OnClickListener. 
  4. Во втором методе-обработчике (onClick) выполняем операцию над выбранным элементом нашего ListView. Для этого объект выбранного элемента нужно получить в первом методе-обработчике (onItemClick) и передать во второй конструктор Operation. 
Схема может показаться запутанной, но исходник, приведенный ниже, думаю, поможет разобраться:

  1. import android.app.Activity;
  2. import android.app.AlertDialog;
  3. import android.content.DialogInterface;
  4. import android.view.View;
  5. import android.widget.AdapterView;
  6. import android.widget.AdapterView.OnItemClickListener;
  7.  
  8. public class Operation implements DialogInterface.OnClickListener, OnItemClickListener {
  9.   
  10.   private Activity act;
  11.   private Object obj;
  12.   private String title;
  13.   private String[] oper_list;
  14.  
  15.   public Operation(Activity act, String title, String[] oper_list) {
  16.     this.act = act;
  17.     this.title = title;
  18.     this.oper_list = oper_list;
  19.   }
  20.  
  21.   public Operation(Activity act, Object obj) {
  22.     this.act = act;
  23.     this.obj = obj;
  24.   }
  25.   
  26.   public void onClick(DialogInterface di, int i) {
  27.     if (i==0) {
  28.       // TODO: first oheration with obj
  29.     }
  30.     // TODO: next operations with obj
  31.   }
  32.  
  33.   public void onItemClick(AdapterView<?> av, View view, int i, long l) {
  34.     Object curr = av.getItemAtPosition(i);
  35.     AlertDialog.Builder builder = new AlertDialog.Builder(act);
  36.     builder.setTitle(title);
  37.     builder.setItems(oper_list, new Operation(act, curr));
  38.     AlertDialog alert = builder.create();
  39.     alert.show();
  40.   }
  41. }
А в том месте, где нужно построить список поступаем просто:
    ListView lw = new ListView(this);
    String[] operations = {"Edit", "Delete"};
    lw.setAdapter(new ArrayAdapter(this, android.R.layout.simple_list_item_1, items));
    lw.setOnItemClickListener(new Operation(this, "Operations", operations));