カスタムviewをxmlで使用する

Android プログラミングで自前で View を継承して作成したカスタムviewをレイアウトファイル(xml)に記述する方法

例えば、時刻を表示するためにTextViewを使っているとして、いちいち

view.setText((new SimpleDateFormat("HH:mm:ss")).format(System.currentTimeMillis())); 

などと書くのが面倒だとする。TextView に表示する時刻を持たせて、

view.setTime(System.currentTimeMillis());

としたら、画面には 12:15:07 とか勝手に表示されて欲しいよね。
でも、レイアウトの配置は固定だからレイアウトxmlファイルに自前で作ったクラスを書きたい。

以下手順

1.まずは適当に TextView を拡張したクラスを作成する

public class TimeView extends TextView {
    private long time;
    private SimpleDateFormat df;

    public TimeView(Context context) {
        this(context, null, 0);
    }

    public TimeView(Context context, AttributeSet attrs) {
        this(context, attrs, 0);
    }

    public TimeView(Context context, AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);
        time = 0;
        df = new SimpleDateFormat("HH:mm:ss");
    }
    
    @Override
    public void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        Date date = new Date(time);
        setText(df.format(date));
    }
    
    public void setTime(long time) {
        if ( time >= 0 ) this.time = time;
        invalidate();
    }
    
    public long getTime() { return time; }
}

注意点

  • TextView の持つ 3種類のコンストラクタを実装する。そうしないと xml ファイルからビューをinflate するところで失敗する

2.作成したクラスをレイアウトファイルに書く

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

    <TextView
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:text="@string/hello" />
    <YOUR_PACKAGE_NAME.TimeView
        android:layout_width="160dp"
        android:layout_height="wrap_content"
        android:layout_gravity="center"
        android:background="#c0c080"
        />
    <Button
        android:id="@+id/nowButton"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_gravity="right"
        android:onClick="setCurrentTime"
        android:text="@string/now" />
</LinearLayout>

注意点

  • xmlns:app 宣言を追加して、自分のアプリケーションのパッケージ名を記載する
  • カスタムビューは完全修飾名で記載する

すると
f:id:koko_u:20120101182407p:plain
な感じで組込みのViewと同じように使える。

3.あとは使うだけ

public class MainActivity extends Activity {
    private TimeView timeView;
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);
        
        timeView = (TimeView)findViewById(R.id.currentTimeView);
    }
    
    public void setCurrentTime(View v) {
        timeView.setTime(System.currentTimeMillis());
    }
}

View 側でいろいろさせることで、MainActiviy がすっきりしてちょっと嬉しい。
f:id:koko_u:20120101182418p:plain

作成したサンプルはここ https://github.com/koko-u/CustomViewSample