AndroidのAdapterViewで、カスタムビューを使っていてもCheckedTextViewなどのチェックをしたい(Spinnerのdropdown等)

AndroidのAdapterViewのAdapterにandroid.R.layout.simple_spinner_dropdown_itemなどを入れると、デフォルトで選択されているものをcheckedにしてくれます。
これは便利なんですが、ちょっと中のレイアウトをいじってLinearLayoutなどをitemの最上位オブジェクトにしてしまうと、チェックをしてくれなくなってしまいます。例えば以下。
foo.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="fill_parent" android:layout_height="wrap_content"
    android:gravity="center_vertical" android:paddingLeft="5dp" android:paddingRight="5dp">
    <ImageView android:id="@+id/FooImageView"
        android:layout_width="wrap_content" android:layout_height="wrap_content" />
    <CheckedTextView android:id="@+id/BarCheckedTextView"
        android:layout_width="fill_parent" android:layout_height="?android:attr/listPreferredItemHeight"
        style="?android:attr/spinnerDropDownItemStyle"
        android:singleLine="true" android:ellipsize="marquee" />
</LinearLayout>

ソースを見てみたところ、Adapterが、対象のitemがCheckableを実装しているかで判別してチェックをしてくれているようです。(android.R.layout.simple_spinner_dropdown_itemは上記のCheckedTextViewと同じものでした)

自前のAdapterの中でチェックを付けたり消したりするのは、Adapter的に(AdapterはデータとAdapterViewの橋渡しをしてりゃいいんだよ的な)よくないと思われるので、素直にカスタムビューを作ってCheckableを実装させることにします。

package jp.funnything.foo.adapter;

import jp.funnything.foo.R;
import android.content.Context;
import android.view.LayoutInflater;
import android.view.View;
import android.widget.Checkable;
import android.widget.CheckedTextView;
import android.widget.LinearLayout;
import android.widget.ListView;

public class SomeDropdownItem extends LinearLayout implements Checkable {
    private CheckedTextView _checkedTextView;

    public SomeDropdownItem( Context context ) {
        super( context );

        setLayoutParams( new ListView.LayoutParams( ListView.LayoutParams.FILL_PARENT ,
                ListView.LayoutParams.WRAP_CONTENT ) );

        View view =
                ( ( LayoutInflater ) context.getSystemService( Context.LAYOUT_INFLATER_SERVICE ) ).inflate(
                        R.layout.foo , this , false );
        _checkedTextView = ( CheckedTextView ) view.findViewById( R.id.BarCheckedTextView );

        addView( view );
    }

    @Override
    public boolean isChecked() {
        return _checkedTextView.isChecked();
    }

    @Override
    public void setChecked( boolean checked ) {
        _checkedTextView.setChecked( checked );
    }

    @Override
    public void toggle() {
        setChecked( !isChecked() );
    }
}

こんな感じにして、Adapter側では

    @Override
    public View getDropDownView( int position , View convertView , ViewGroup parent ) {
        View view = convertView;

        if ( view == null ) {
            // よくあるパターンはこう
            /*
             * view = ( ( LayoutInflater ) getContext().getSystemService( Context.LAYOUT_INFLATER_SERVICE ) ).inflate(
             * R.layout.currency_spinner_dropdown_item , parent , false );
             */
            view = new SomeDropdownItem( getContext() );
        }

        String item = getItem( position );

        ImageView fooImageView = ( ImageView ) view.findViewById( R.id.FooImageView );
        CheckedTextView barCheckedTextView = ( CheckedTextView ) view.findViewById( R.id.BarCheckedTextView );

        // 適当にコンポーネントをいじる

        return view;
    }

としてやると動きました。


これだけなんですが、結構嵌ったのでメモ。
嵌りどころとしては、カスタムビューでinflateするときに
inflate( resId , null )だとinflateされたリソースのlayout_width,layout_heightがwrap_contentになってしまうっぽいので、
inflate( resId , this , false )とするあたりとかに嵌りました。