понедельник, 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 - наш массив контактов.

1 комментарий: