2011年1月19日水曜日

オブジェクト指向な ListView の使い方(前編)

以下のような ListView のサンプルがあったとします。
package com.blogspot.androlab.example;

import java.text.DateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Locale;

import android.app.Activity;
import android.os.Bundle;
import android.widget.ArrayAdapter;
import android.widget.LinearLayout;
import android.widget.ListView;

/** メインアクティビティです。 */
public class MainActivity extends Activity {
 protected void onCreate(Bundle savedInstanceState) {
  super.onCreate(savedInstanceState);

  List<Schedule> scheduleList = new ArrayList<Schedule>();

  // リストに値を挿入
  scheduleList.add(new Schedule("2011/01/19", "通常業務", "業務報告", "懇談会"));
  scheduleList.add(new Schedule("2011/01/20", "通常業務", "業務報告"));
  scheduleList.add(new Schedule("2011/01/21", "通常業務", "週末報告", "日本 vs カタール"));
  scheduleList.add(new Schedule("2011/01/24", "朝礼", "工場視察"));

  // リストに表示する文字列を配列に格納
  List<String> sList = new ArrayList<String>(scheduleList.size());
  for (Schedule s : scheduleList)
   sList.add(s.getDateString() + " [ " + s.size() + "件 ]");

  // 作成した配列で ArrayAdapter を作成
  ArrayAdapter<String> arrayAdapter = new ArrayAdapter<String>(this, android.R.layout.simple_list_item_1, sList);

  // ListView を作成
  ListView listView = new ListView(this);
  listView.setAdapter(arrayAdapter);

  // レイアウト
  LinearLayout linearLayout = new LinearLayout(this);
  linearLayout.addView(listView, new LinearLayout.LayoutParams(
    LinearLayout.LayoutParams.FILL_PARENT, LinearLayout.LayoutParams.WRAP_CONTENT));
  setContentView(linearLayout);
 }
}

/** 日程クラスです。 */
class Schedule extends ArrayList<Task> {
 private static final long serialVersionUID = 1L;
 private Date mDate;
 Schedule(String date, String... tasks) {
  mDate = new Date(date);
  for (String task : tasks) add(new Task(task));
 }
 String getDateString() {
  DateFormat df = DateFormat.getDateInstance(DateFormat.LONG, Locale.JAPANESE);
  return df.format(mDate);
 }
}

/** 仕事の最小単位です。 */
class Task {
 private String mSubject;
 Task(String subject) {
  mSubject = subject;
 }
 public String toString() {
  return mSubject;
 }
}

実行結果

スケジュールの日にち(Schedule#getDateString())と件数(Schedule#size())が、一行づつ出力されています。
このほかに、内容(Task t = Schedule#get(n))を含めて表示させたいときは、どうしたらよいでしょうか。

強引に30行目付近を、
sList.add(s.getDateString() + " [ " + s.size() + "件 ]\n" + s.get(0) + ", " + s.get(1));
のようにして、文字列を連結してしまうことも可能ですが、ちょっとかっこ悪いですよね。

こういうときは、ArrayAdapter#getView(int, View, ViewGroup) をオーバライドして対応させると、非常にスマートになります。

package com.blogspot.androlab.example;

import java.text.DateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Locale;

import android.app.Activity;
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ArrayAdapter;
import android.widget.LinearLayout;
import android.widget.ListView;
import android.widget.TextView;
import android.widget.TwoLineListItem;

public class MainActivity extends Activity {
 protected void onCreate(Bundle savedInstanceState) {
  super.onCreate(savedInstanceState);

  List<Schedule> scheduleList = new ArrayList<Schedule>();

  // リストに値を挿入
  scheduleList.add(new Schedule("2011/01/19", "通常業務", "業務報告", "懇談会"));
  scheduleList.add(new Schedule("2011/01/20", "通常業務", "業務報告"));
  scheduleList.add(new Schedule("2011/01/21", "通常業務", "週末報告", "日本 vs カタール"));
  scheduleList.add(new Schedule("2011/01/24", "朝礼", "工場視察"));

  // 作成した配列で ArrayAdapter を作成
  ArrayAdapter<Schedule> arrayAdapter = new ArrayAdapter<Schedule>(this, 0, scheduleList) {
   private LayoutInflater mInflater;
   // 初期化子(コンストラクタの代わり)
   {
    mInflater = (LayoutInflater) getSystemService(LAYOUT_INFLATER_SERVICE);
   }
   // 表示する「一行分のView」を返すメソッド
   @Override
   public View getView(int position, View convertView, ViewGroup parent) {
    // 表示する一行分のViewには、android.R.layout.simple_list_item_2
    // (中身は TwoLineListItem) を利用する
    Schedule s = getItem(position);
    TwoLineListItem view = (TwoLineListItem) mInflater.inflate(android.R.layout.simple_list_item_2, null);

    // 1/2行分のTextView(上部)
    TextView text1 = view.getText1();
    text1.setText(s.getDateString() + " [ " + s.size() + "件 ]");

    // 1/2行分のTextView(下部)
    TextView text2 = view.getText2();
    text2.setSingleLine(true);
    String tasks = ""; for (Task t : s) tasks += t + ", ";
    text2.setText(tasks.substring(0, tasks.length() - 2));

    return view;
   }
  };

  // ListView を作成
  ListView listView = new ListView(this);
  listView.setAdapter(arrayAdapter);

  // レイアウト
  LinearLayout linearLayout = new LinearLayout(this);
  linearLayout.addView(listView, new LinearLayout.LayoutParams(
    LinearLayout.LayoutParams.FILL_PARENT, LinearLayout.LayoutParams.WRAP_CONTENT));
  setContentView(linearLayout);
 }
}

/** 日程クラスです。 */
class Schedule extends ArrayList<Task> {
 private static final long serialVersionUID = 1L;
 private Date mDate;
 Schedule(String date, String... tasks) {
  mDate = new Date(date);
  for (String task : tasks) add(new Task(task));
 }
 String getDateString() {
  DateFormat df = DateFormat.getDateInstance(DateFormat.LONG, Locale.JAPANESE);
  return df.format(mDate);
 }
}

/** 仕事の最小単位です。 */
class Task {
 private String mSubject;
 Task(String subject) {
  mSubject = subject;
 }
 public String toString() {
  return mSubject;
 }
} 

実行結果
うまくいきました。
プログラムの保守性も考えて、なるべく、オブジェクト単位で処理していきたいですね。

次回は、リスト選択時のアイテムの扱い方をご紹介します。

0 件のコメント:

コメントを投稿