SIN@SAPPOROWORKSの覚書

C#を中心に、夜な夜な試行錯誤したコードの記録です。

Xamarin.Android ActionBar(その3 ドロップダウン リスト)

【 Xamarin 記事一覧 】


1 リストモード


ActionBarのNavigationModeを「ActionBarNavigationMode.List」にセットすることで、アクションバーにリスト(ドロップダウンリスト)を追加することができます。

最初にテキストのみのリストの例です。
SetListNavigationCallbacksでリストのアダプタと選択時のリスナーをセットするだけです。

[Activity(Label = "AndroidApplication1", MainLauncher = true, Icon = "@drawable/icon")]
public class MainActivity : Activity, ActionBar.IOnNavigationListener{

    protected override void OnCreate(Bundle bundle){
        base.OnCreate(bundle);

        ActionBar.NavigationMode = ActionBarNavigationMode.List; //リスト表示モード

        SetContentView(Resource.Layout.Main);

        // アダプタを作成する
        var adapter = new ArrayAdapter(this, Android.Resource.Layout.SimpleListItem1);
        for (var i = 0; i < 5; i++) {
            adapter.Add("item_" + i);
        }
        // ナビゲーションにアダプタとコールバックをセットする
        ActionBar.SetListNavigationCallbacks(adapter, this);
    }

    //リスト選択時のイベント
    public bool OnNavigationItemSelected(int itemPosition, long itemId){
        Toast.MakeText(this, itemPosition.ToString(), ToastLength.Short).Show();
        return true;
    }
}

2 独自のドロップダウンリスト

(1) ArrayAdapter


自前でアダプタを作成することで、自由なリストを作成できます。
要領は、ListViewの「表示内容のカスタマイズ」と同じです。
最初に1つのアイテムのデータ型(ListItem)を設計します。

public class ListItem{
    public String Title; 
    public Bitmap Icon;
}

続いてArrayAdapterを継承した、Adapter用のクラスです。
なお、ここで GetDropDownView()をオーバーライドして、Viewを適切に設定しないと、ドロップダウン時に例外が発生します。

public class MyAdapter : ArrayAdapter<ListItem> {

    private readonly LayoutInflater _layoutInflater;
    public MyAdapter(Context context, int rid, IList<ListItem> list)
        : base(context, rid, list) {
         _layoutInflater = (LayoutInflater)context.GetSystemService(LayoutInflaterService);
    }

    public override View GetView(int position, View convertView, ViewGroup parent) {
        //データを取り出す
        var item = GetItem(position);
       
        //レイアウトファイルからViewを作成
        var view = _layoutInflater.Inflate(Resource.Layout.list_item, null);
        var image = view.FindViewById<ImageView>(Resource.Id.imageIcon);
        image.SetImageBitmap(item.Icon);
        var textViewName = view.FindViewById<TextView>(Resource.Id.textViewTitle);
        textViewName.Text = item.Title;

        return view;
    }

    //ArrayAdapterを使用する場合は、これをoverrideして自前でviewを作成する必要がある
    public override View GetDropDownView(int position, View convertView, ViewGroup parent){
        //convertViewがnullでも、GetViewの中で確保されるため、そのまま送っておく
        return GetView(position, convertView, parent);
    }
}

1アイテム用のxmlです。
xmlは、ListViewの時と違って、適切な padding や margin を設定しないと、ドロップダウンの見た目が醜くなるので気を使う必要があります。
左図は、ちょっと詰まってしまった例で、下記は、padding等を調整したxml例です。

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="horizontal"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
   android:padding="10dp" >
    <ImageView android:id="@+id/imageIcon"
        android:layout_width="25dp"
        android:layout_height="25dp"
        android:layout_alignParentLeft="true"
        android:layout_alignParentTop="true"
        android:layout_marginRight="5dp"
        />
    <TextView android:id="@+id/textViewTitle"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_centerVertical="true"
        />
</LinearLayout>

最後に使い方です。

// アダプタ用のデータ作成
var ar = new List<ListItem>();
var icEdit = BitmapFactory.DecodeResource(Resources, Android.Resource.Drawable.IcMenuEdit);
ar.Add(new ListItem(){Title = "Edit", Icon = icEdit});
var icDelete = BitmapFactory.DecodeResource(Resources, Android.Resource.Drawable.IcMenuDelete);
ar.Add(new ListItem(){Title = "Delete", Icon = icDelete});
var icSave = BitmapFactory.DecodeResource(Resources, Android.Resource.Drawable.IcMenuSave);
ar.Add(new ListItem(){Title = "Save", Icon = icSave});
var icUpload = BitmapFactory.DecodeResource(Resources, Android.Resource.Drawable.IcMenuUpload);
ar.Add(new ListItem(){Title = "Upload", Icon = icUpload});

//アダプタの作成
var myAdapter = new MyAdapter(this, ar);

// ナビゲーションにアダプタとリスナーをセット
ActionBar.SetListNavigationCallbacks(myAdapter, this);

(2) BaseAdapter

参考のためにArrayAdapterの代わりにBaseAdapterを使用した例を載せておきます。
こちらの場合は、GetDropDownViewのoverrideは必須ではありません。

GetView()内でのデータの取り出しに、GetItem(position)を使用すると Java.Lang.Object型 になるため厄介です。
迷わず _list[position] を使用しましよう。

public class MyAdapter : BaseAdapter{
            private readonly IList<ListItem> _list;//BaseAdapterの場合は、自前でListを保持する
            private readonly LayoutInflater _layoutInflater;

            public MyAdapter(Context context, IList<ListItem> list) {
                _list = list;
                _layoutInflater = LayoutInflater.FromContext(context);
            }
            public override View GetView(int position, View convertView, ViewGroup parent){

                //データを取り出す
                //GetItem(position)でデータを取り出すとJava.Lang.Objectになるため、後々使用しづらいので
                //_list[position]で取り出す
                var item = _list[position];
                
                var view = convertView;
                if (view == null){
                    //レイアウトファイルからViewを作成
                    view = _layoutInflater.Inflate(Resource.Layout.list_item, parent, false);
                }

                var textView = view.FindViewById<TextView>(Resource.Id.textViewTitle);
                textView.Text = item.Title;

                var imageView = view.FindViewById<ImageView>(Resource.Id.imageIcon);
                imageView.SetImageBitmap(item.Icon);

                return view;
            }
            //BaseAdapterがAbstractであるためoverrideが必須のメソッド
            public override Java.Lang.Object GetItem(int position) {
                return null;
            }
            //BaseAdapterがAbstractであるためoverrideが必須のメソッド
            public override long GetItemId(int position) {
                return position;
            }
            //BaseAdapterがAbstractであるためoverrideが必須のメソッド
            public override int Count {
                get { return _list.Count(); }
            }
        }
    }

【 Xamarin 記事一覧 】