2011年5月22日日曜日

Androidの基本 ListViewを使う

今回は、基本に戻ってListViewを使った画面の作成について書いてみる。がしかし、それだけでは面白くないので一切の画像ファイルを使わずに実現してみる。出来上がりのイメージはこんな感じ。


やること

  • 画面のレイアウト定義
  • 1行分のレイアウト定義
  • リストアダプタの作成
  • アクティビティクラスの作成

画面のレイアウト定義

画面のレイアウトはシンプルに、ListViewのみを配置した形に定義する。同じことを実現するためにListActivityというのが用意されているが、使用するメリットが薄い上にこれ系のクラス(TabActivityとか)には問題があったりもするので使わない。

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
  xmlns:android="http://schemas.android.com/apk/res/android"
  android:orientation="vertical"
  android:layout_width="fill_parent"
  android:layout_height="fill_parent">
    <ListView
      android:id="@+id/listview"
      android:layout_width="fill_parent"
      android:layout_height="fill_parent"/>
</LinearLayout>

1行分のレイアウト定義

ListViewは、各行のレイアウトを自由にカスタマイズすることができる。単純に文字だけを表示するならAndroid標準で用意されているレイアウトを使うことも可能。

今回は、右端に三角形のマークを表示したいので、下記のようにLinearLayoutを定義、子要素としてTextViewとカスタムビューを配置する。TextViewにはlayout_weight="1"のオマジナイがしてあるのでTextViewの領域は限界まで広がり、残りの部分に三角形マークが配置される。

<?xml version="1.0" encoding="UTF-8"?>  
<LinearLayout 
  xmlns:android="http://schemas.android.com/apk/res/android"  
  xmlns:tomokey="http://schemas.android.com/apk/res/com.tomokey"
    android:layout_width="fill_parent" 
    android:layout_height="wrap_content" 
    android:orientation="horizontal"
    android:gravity="center_vertical" >
    
    <TextView 
      android:id="@+id/row_text" 
      android:layout_height="wrap_content"
      android:layout_width="wrap_content"  
      android:layout_weight="1"
      android:textColor="@android:color/white"
      android:textSize="20dip"
      android:minHeight="50dip"
      android:gravity="center_vertical"/>
  
    <com.tomokey.custom.view.Triangle
      android:id="@+id/tri"
      android:layout_width="7dip"
      android:layout_height="15dip"
      tomokey:color="@android:color/white"
      tomokey:direction="right"
      />
    
</LinearLayout>
※画像を使わない縛りがあるために、com.tomokey.custom.view.Triangleというカスタムビューを利用している。俺は画像を使っちゃうぜ!って場合はImageViewとかにしておけばOK。

リストアダプタの作成

リストアダプタ(ListAdapter)はその名の通り、データとListViewを繋ぐためのもの。今回は配列データとListViewを繋ぐためのArrayAdapterを使って下記のようにリストアダプタを作成する。

ArrayAdapterのコンストラクタには、1行分のレイアウト定義とTextViewを指し示すIDを指定する。ArrayAdapterをそのまま利用する場合には、1行分のレイアウト定義にTextViewが含まれていなければならないし、そのTextViewにはIDが設定されていなければならない。

ListAdapter adapter
  = new ArrayAdapter<String>(
    this,
    R.layout.row,
    R.id.row_text,
    DATA)

上記のコードで利用しているDATAはこんな感じ。

private static final List<String> DATA
  = Arrays.asList(new String[]{
          "Google",
          "Apple",
          "Microsoft",
          "Research In Motion",
          "Palm"
    });

アクティビティクラスの作成

お決まりのコード達に加えて、ListViewウィジェットへリストアダプタを設定するコード(setAdapter)を追加する。

@Override
public void onCreate(Bundle savedInstanceState)
{
  super.onCreate(savedInstanceState);

  // 画面のレイアウト定義を設定
  setContentView(R.layout.main);
  
  // ListViewウィジェットを取得
  mListView = (ListView) findViewById(R.id.listview);

  // この辺りで「リストアダプタの作成」をしておく

  // リストアダプタを設定
  mListView.setAdapter(adapter);
}

三角形マークは画像で行くぜ!って場合はここまでで終わり。ここからは、三角形をプログラムのみで実現する方法。

三角形のためにやること

  • 三角形のプロパティ設計
  • カスタムビュークラスの作成

三角形のプロパティ設計

設計などと仰々しく書いてみたけど、単純に三角形を使うとき何が変えられたら便利かを考えてXMLを書くだけ。今回は以下のように定義してみた。

変えられたら便利なとこ

三角形の色 三角形の方向

XML - res/values/attrs.xml

<?xml version="1.0" encoding="utf-8"?>
<resources>
  <declare-styleable name="Triangle">
    <attr name="color" format="color" />
    <attr name="direction">
      <enum name="right" value="0"/>
      <enum name="left" value="1"/>
      <enum name="top" value="2"/>
      <enum name="bottom" value="3"/>
  </attr>
  </declare-styleable>
</resources>

Triangleという名前のカスタムビューについて、colorとdirectionという名前のプロパティを定義している。また、directionについては「right」「left」「top」「bottom」のいずれかが設定できて、それぞれ数字の0~3の値を持っている。

カスタムビュークラスの作成

カスタムビューとは、Androidアプリの各ウィジェットの基礎になっているViewクラスを独自に拡張して作成した、世界でたった一つの私だけのビュー・・・だ。以下、簡潔に。

定義
package com.tomokey.custom.view;

public class Triangle extends View
定数
// 三角形の方向
public final static int DIRECTION_RIGHT = 0;
public final static int DIRECTION_LEFT = 1;
public final static int DIRECTION_TOP= 2;
public final static int DIRECTION_BOTTOM = 3;
インスタンス変数
// 描画オブジェクト
private Paint mPaint;

// 三角形の色
private int mColor;

// 三角形の方向
private int mDirection;
コンストラクタ
public Triangle(Context context, AttributeSet attrs)
{
  super(context, attrs);

  // 描画オブジェクトを初期化
  mPaint = new Paint();
  mPaint.setAntiAlias(true);
  
  // XMLで定義されたプロパティ値を取得
  TypedArray a =
    context.obtainStyledAttributes(
        attrs,
        R.styleable.Triangle);
  
  // 三角形の色を取得(デフォ:白)
  mColor 
    = a.getColor(
        R.styleable.Triangle_color,
        0xFFFFFFFF);
  
  // 三角形の方向を取得(デフォ:右)
  mDirection
    = a.getInt(
        R.styleable.Triangle_direction,
        DIRECTION_RIGHT);
}
プログラムから色を設定するメソッド
public void setColor(String color)
{
  mColor = Color.parseColor(color);
  requestLayout();
  invalidate();
}
ビューの描画メソッド
@Override
protected void onDraw(Canvas canvas)
{
  super.onDraw(canvas);
  
  // 三角形の色を設定
  mPaint.setColor(mColor);
  
  // 三角形の方向に応じてパスを生成
  Path triangle = new Path();
  switch (mDirection)
  {
  case DIRECTION_RIGHT:
    // 左上から
    triangle.moveTo(0, 0);
    // まっすぐ左下へ
    triangle.lineTo(0, getMeasuredHeight());
    // んで、右端の高さは真ん中へ
    triangle.lineTo(getMeasuredWidth(), (getMeasuredHeight() / 2));
    break;
    
  case DIRECTION_LEFT:
    triangle.moveTo(getMeasuredWidth(), 0);
    triangle.lineTo(getMeasuredWidth(), getMeasuredHeight());
    triangle.lineTo(0, (getMeasuredHeight() / 2));
    break;
    
  case DIRECTION_TOP:
    triangle.moveTo(0, getMeasuredHeight());
    triangle.lineTo(getMeasuredWidth(), getMeasuredHeight());
    triangle.lineTo((getMeasuredWidth() / 2), 0);
    break;
    
  case DIRECTION_BOTTOM:
    triangle.moveTo(0, 0);
    triangle.lineTo(getMeasuredWidth(), 0);
    triangle.lineTo((getMeasuredWidth() / 2), getMeasuredHeight());
    break;
  }
  
  // パスを塗りっと
  canvas.drawPath(triangle, mPaint);
}

0 件のコメント:

コメントを投稿