fc2ブログ

戌印-INUJIRUSHI- (Androidあれこれ)

Androidのプログラミングをメインにしてます。記事に貼られたソースコードはダブルクリックすることで行番号をはずしてコピーすることができます。

 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
06

ListView をカスタマイズする

情報を一覧表示する ListView ですが、アプリを作るとなると既存のレイアウトでは少し物足りなくなってしまいます。
そこで今回は ListView のカスタマイズの方法を紹介します。

カスタマイズの説明については、以下の手順で説明します。

①行のレイアウトを定義する
②レイアウトを表示するAdapterクラスを作成する
③アクティビティにカスタマイズしたListViewを配置する

■ 完成イメージ -----------------------------------------------
さて、いきなり手順から離れてしまいますが(手順には書きませんでしたが)
カスタマイズする前にどのようなレイアウトにするか考えなければいけません。

今回は簡単ですが、左端に画像、そのすぐ右に文字列を表示するレイアウトを作成します。
完成イメージはこんな感じです。
android_ListView_custom1.png

■ 行レイアウトを定義する ------------------------------------
カスタマイズ作業にあたって、まず始めに ListView に表示する行のレイアウトを定義します。
完成イメージで書いたように画像を表示するレイアウトを作成します。

sample_row.xml
<?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="wrap_content"
android:orientation="horizontal" >
<ImageView
android:id="@+id/imageView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:padding="6dp" />
<TextView
android:id="@+id/textView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
android:layout_weight="1"
android:textSize="24sp" />
</LinearLayout>

※ 小さな画像を表示することを前提としているため、画像サイズは指定していません

■ ArrayAdapterを定義する ------------------------------------
次に ListView を表示するための Adapter クラスを定義します。
ArrayAdapter や SimpleAdapter など色々な Adapter がありますが、ここでは ArrayAdapter クラスを使用します。

Adapterクラスを作成するにあたって、以下の点に注意してください。
①行の値は毎回設定する必要がある
Adapterクラスには、行を表示するための View を返すメソッドとして getView() があります。
しかし、ここで表示される View(第2引数の convertView)は画面外に行ったViewを再利用しているため正しい順番で表示されるとは限りません(再描画やスクロールをすると前回と違う順番で表示されます)。
そこで、行位置(第1引数の position)を元に getItem(position) で行の正しい情報を取得して View の要素を書き換える必要があります。

参考サイト:hyoromoの日記 - Adapter#getViewの挙動について

②ViewHolderを使用して高速化する
ViewHolderとは ListView を高速化するために View 要素を使いまわす手法を言います(たぶん)
毎行、レイアウト定義したXMLをインフレートするとパフォーマンスが落ちてしまうので、XMLで定義されているViewを保持する独自クラスを作成、使用して処理を簡略化します。

と、このような問題を考慮してAdapterクラスを作成します。
ここで作られるクラスは1つのファイルですが、クラスは3つ定義しています(分けてもOK)

CustomAdapter :メインのAdapterクラス
ViewHolder :②で説明したやつ
SampleData :Adapterに表示する情報をまとめたクラス

CustomAdapter.java
package jp.inujirushi.sample.activity;

import java.util.List;

import jp.inujirushi.sample.R;
import android.content.Context;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ArrayAdapter;
import android.widget.ImageView;
import android.widget.TextView;

public class CustomAdapter extends ArrayAdapter {

LayoutInflater mInflater;

/**
* コンストラクタ
*
* @param context
* コンテキスト
* @param objects
* 行データ
*/
public CustomAdapter(Context context, List objects) {
// 親のコンストラクタを呼び出す
// ※ 2番目の引数はレイアウトのリソースIDだがgetViewで指定するのでここでは0を設定
super(context, 0, objects);

// インフレーターを取得する
this.mInflater = (LayoutInflater) context
.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
}

@Override
public View getView(int position, View convertView, ViewGroup parent) {
// ホルダークラスを定義する
// ※ ホルダークラスを使うことで再表示時にレイアウト内のビュー検索が無くなり高速化されます
ViewHolder holder;

// ビューを設定する
if (convertView == null) {
// はじめて呼ばれた時はビューはnullが設定されている
// ビューに定義したレイアウトをインフレートする
convertView = this.mInflater.inflate(R.layout.sample_row, parent,
false);

// ホルダークラスを生成する
holder = new ViewHolder();

// ホルダークラスにレイアウト内のビューを設定する
holder.textView = (TextView) convertView
.findViewById(R.id.textView);
holder.imageView = (ImageView) convertView
.findViewById(R.id.imageView);

// タグにホルダークラスを設定する
convertView.setTag(holder);
} else {
// 2回目以降はビューが設定されている
// タグからホルダークラスを取得する
holder = (ViewHolder) convertView.getTag();
}

// 指定された位置のアイテムを取得する
SampleData data = getItem(position);

// ホルダークラスのビューの値を設定する
// ※ convertViewに設定されている内容とgetItem(position)の内容が同じではないので再設定が必要
holder.imageView.setImageResource(data.resourceId);
holder.textView.setText(data.text);

// 表示するビューを返す
return convertView;
}

/**
* ホルダクラス
*/
class ViewHolder {
/** イメージビュー */
ImageView imageView;

/** テキストビュー */
TextView textView;
}
}

/**
* アダプタに設定するデータ
*/
class SampleData {
/** 画像のリソースID */
int resourceId;

/** 文字列 */
String text;

/**
* コンストラクタ
*
* @param resourceId
* 画像のリソースID
* @param text
* 文字列
*/
public SampleData(int resourceId, String text) {
this.resourceId = resourceId;
this.text = text;
}
}


■ アクティビティにListViewを配置する --------------------------
カスタマイズした Adapter クラスを使用した ListView を表示するためのレイアウトXMLを定義します。
といっても、カスタマイズしたのは表示処理の任されている Adapter クラスのため、受け皿は普通の ListView を使います。

アクティビティクラスは特に説明なし。
画像は特に考えずにプロジェクト作成時に作られるアイコンをひたすら表示させているだけです。

sample_listview.xml
<?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="match_parent"
android:orientation="vertical" >

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

</LinearLayout>


CustomListActivity.java
package jp.inujirushi.sample.activity;

import java.util.ArrayList;
import java.util.List;

import jp.inujirushi.sample.R;
import android.app.Activity;
import android.os.Bundle;
import android.widget.ListView;

public class CustomListActivity extends Activity {

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

// リストビューに表示する項目を生成する
List list = new ArrayList();
for (int i = 0; i < 10; i++) {
list.add(new SampleData(R.drawable.icon, "項目" + i));
}

// リストビューを取得する
ListView listView = (ListView) findViewById(R.id.listView);

// リストビューにカスタムしたリストアダプタを設定する
listView.setAdapter(new CustomAdapter(this, list));
}
}


とまあ、こんな感じ。
スポンサーサイト




Comments

Leave a Comment


Body
プロフィール

とむ・やむくん

Author:とむ・やむくん
管理人について

Windows 7 / 64bit
Eclipse 4.2 Juno (日本語パッチ済)

スポンサーサイト
最新トラックバック
検索フォーム
ブロとも申請フォーム
QRコード
QR
Twitter
2013/01/04 19:00 カウント開始