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

前回(d:id:koko_u:20120101)は自分で作成した CustomView クラスをメイン側の xml ファイルに指定するにはどうすれば?という話でしたが、今回はCustomView を作成する時もそのレイアウトは xml ファイルでちょこちょこ作りたいね。という話。

例えばこーんな感じの画面を作成するとして、

中央の3x3タイルは独立して BoardView を作成して、メイン側ではどのタイルが押されたかに応じて

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);

        resultView = (TextView)findViewById(R.id.resultView);
        boardView = (BoardView)findViewById(R.id.boardView);
        boardView.setOnClickListener(new BoardView.OnClickedListener() {
            @Override
            public void onClick(WHERE where) {
                switch (where) {
                case TL:
                    resultView.setText(getString(R.string.you_clicked, getString(R.string.TL)));
                    break;
                case TC:
                    resultView.setText(getString(R.string.you_clicked, getString(R.string.TC)));
                    break;
                // 中略
                default:
                    resultView.setText("");
                    break;
                }
            }
        });
    }
}

な風にしてみたい。


特に難しいことはなくて、BoardView で使いたいレイアウトを普通に xml ファイルで用意します。
今回トップを TableLayout にしましたが、お好きなもので

<?xml version="1.0" encoding="utf-8"?>
<TableLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent" >

    <TableRow
        android:layout_width="wrap_content"
        android:layout_height="wrap_content" >

        <TextView
            android:id="@+id/tlView"
            android:text="TL"
            style="@style/cell_view" />

        <TextView
            android:id="@+id/tcView"
            android:text="TC" 
            style="@style/cell_view"/>

        <TextView
            android:id="@+id/trView"
            android:text="TR"
            style="@style/cell_view" />

    </TableRow>

    <TableRow
        android:layout_width="wrap_content"
        android:layout_height="wrap_content" >

        <TextView
            android:id="@+id/clView"
            android:text="CL"
            style="@style/cell_view" />

        <TextView
            android:id="@+id/ccView"
            android:text="CC" 
            style="@style/cell_view"/>

        <TextView
            android:id="@+id/crView"
            android:text="CR"
            style="@style/cell_view" />

    </TableRow>

    <TableRow
        android:layout_width="wrap_content"
        android:layout_height="wrap_content" >

        <TextView
            android:id="@+id/blView"
            android:text="BL"
            style="@style/cell_view" />

        <TextView
            android:id="@+id/bcView"
            android:text="BC" 
            style="@style/cell_view"/>

        <TextView
            android:id="@+id/brView"
            android:text="BR"
            style="@style/cell_view" />

    </TableRow>

</TableLayout>

同じセルがずらずら並んでいるだけなので、見た目は全部 style として別ファイルにしました

<?xml version="1.0" encoding="utf-8"?>
<resources>
    <style name="cell_view">
        <item name="android:layout_height">40dp</item>
        <item name="android:layout_width">40dp</item>
        <item name="android:clickable">true</item>
        <item name="android:gravity">center</item>
        <item name="android:padding">5dp</item>
        <item name="android:textSize">24sp</item>
        <item name="android:background">@drawable/rectangle</item>
    </style>
</resources>

今回の話には関係ないです。/res/values の下に適当な名前で保存。

で、このレイアウト(nine_board.xml)を使用するカスタムビューを BoardView として作成

public class BoardView extends TableLayout {
    public enum WHERE {
        TL, TC, TR,
        CL, CC, CR,
        BL, BC, BR
    };
    private LayoutInflater inf;
    private OnClickedListener listener;
    private TextView TLView, TCView, TRView, 
                     CLView, CCView, CRView, 
                     BLView, BCView, BRView;

    public BoardView(Context context) {
        this(context, null);
    }

    public BoardView(Context context, AttributeSet attrs) {
        super(context, attrs);
        inf = (LayoutInflater)context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
        View layout = inf.inflate(R.layout.nine_board, this);
        TLView = (TextView)layout.findViewById(R.id.tlView);
        TLView.setOnClickListener(new OnClickListener() {
            @Override
            public void onClick(View v) {
                listener.onClick(WHERE.TL);
            }
        });
        TCView = (TextView)layout.findViewById(R.id.tcView);
        TCView.setOnClickListener(new OnClickListener() {
            @Override
            public void onClick(View v) {
                listener.onClick(WHERE.TC);
            }
        });
        // おなじなので省略
    }

    public void setOnClickListener(OnClickedListener l) {
        this.listener = l;
    }

    interface OnClickedListener {
        public void onClick(WHERE where);
    }
}

ポイントは、作成した nine_board.xml のトップを TableLayout で作成したので、カスタムビューも TableLayout を継承して作成する。
LayoutInflater#inflate を呼び出す時の第2引数として this 自分自身を指定する。

くらいですかね。OnClickListener はまあ適当。作ったカスタムビューをメインのレイアウトで

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schamas.android.com/apk/res/com.sample.kokou"
    android:id="@+id/RelativeLayout1"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    android:orientation="vertical" >

    <EditText
        android:id="@+id/resultView"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_alignParentLeft="true"
        android:layout_alignParentTop="true"
        android:layout_margin="10dp"
        android:textSize="20sp" >
    </EditText>

    <com.sample.kokou.BoardView
        android:id="@+id/boardView"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_below="@+id/resultView"
        android:layout_centerHorizontal="true" >
    </com.sample.kokou.BoardView>

</RelativeLayout>

な感じで指定すれば、普通に独立したビューとして利用できます。

作ったサンプル https://github.com/koko-u/CustomViewFromXML