こんにちは。エクセルソフトの田淵です。
先日はまずは一番シンプルな単一行の SimpleListItem1 をセルにした ListView にデータを追加したり削除したりしました。
今回は独自のセルを用意してデータ追加、削除を行ってみます。こんな感じです。
サンプルは以下に置いておきました。
セルの CustomView を作成
Android の ListView には Adapter とセルの View が必要です。公式ページ の Sample Code「CustomRowView」をベースにしています。
最初に View を用意します。
View は普通に Layout axml です。新規にレイアウトを作成し、任意のレイアウトを組んでください。今回は左に ImageView、右に縦に TextView を2つ並べ、一番右側に iOS っぽい矢印を入れてます。
こんな感じ。RelativeLayout
で最初に ImageView
を配置。2つの TextView
を layout_toRightOf="@+id/Image"
や layout_below="@id/NameText"
を使って並べていきます。
<?xml version="1.0" encoding="utf-8"?> <RelativeLayout xmlns:p1="http://schemas.android.com/apk/res/android" p1:layout_width="match_parent" p1:layout_height="match_parent" p1:id="@+id/relativeLayout1"> <ImageView p1:src="@drawable/Icon" p1:layout_width="64dp" p1:layout_height="64dp" p1:paddingRight="8dp" p1:paddingLeft="8dp" p1:id="@+id/Image" /> <TextView p1:text="Name" p1:textAppearance="?android:attr/textAppearanceLarge" p1:layout_width="match_parent" p1:layout_height="wrap_content" p1:id="@+id/NameText" p1:layout_toRightOf="@+id/Image" p1:paddingTop="8dp" p1:paddingRight="32dp" /> <TextView p1:text="Age" p1:textAppearance="?android:attr/textAppearanceMedium" p1:layout_width="match_parent" p1:layout_height="wrap_content" p1:layout_toRightOf="@+id/Image" p1:layout_below="@id/NameText" p1:id="@+id/AgeText" p1:paddingRight="32dp" /> <TextView p1:text=">" p1:textAppearance="?android:attr/textAppearanceMedium" p1:layout_width="wrap_content" p1:layout_height="wrap_content" p1:id="@+id/RightArrow" p1:layout_alignParentRight="true" p1:layout_centerVertical="true" p1:padding="16dp" /> </RelativeLayout>
RelativeLayout については こちらの記事 が詳しいです。
BaseAdapter のクラスを作成
CustomAdapter は BaseAdapter<T>
を継承して作成しますので、先ほど作成した CustomView の各項目に割り当てる型を用意します。今回は Image 1、string *2 なので次の TableItem.cs
を用意しました。
public class TableItem { public string Name { get; set; } public string Description { get; set; } public int ImageResourceId { get; set; } }
Image は今回 Xamarin のサンプルに習い .SetImageResource(int resId)
を使用したので int
で用意しましたが、.SetImageBitmap(Android.Graphic.Bitmap bm)
や .SetImageURI(Android.Net.Uri uri)
を使用する場合は適切な型を指定します(すみません。Android.Net.Uri
はまだ使い方が良く分かってなく…)。
CustomAdapter を作成
クラスを作成し、BaseAdapter<TableItem>
を継承します。
Visual Studio であれば、必要なメソッドを用意してくれますので、それぞれに実装します。Xamarin のサンプルに習い次のように実装しました。
public class CustomListAdapter : BaseAdapter<TableItem> { List<TableItem> items; Activity context; public CustomListAdapter(Activity context, List<TableItem> items) { this.context = context; this.items = items; } public override long GetItemId(int position) { return position; } public override TableItem this[int position] { get { return items[position]; } } public override int Count { get { return items.Count; } } public override View GetView(int position, View convertView, ViewGroup parent) { var item = items[position]; View view = convertView; if (view == null) // no view to re-use, create new view = context.LayoutInflater.Inflate(Resource.Layout.CustomView, null); // BaseAdapter<T>の対応するプロパティを割り当て view.FindViewById<TextView>(Resource.Id.NameText).Text = item.Name; view.FindViewById<TextView>(Resource.Id.AgeText).Text = item.Description.ToString(); view.FindViewById<ImageView>(Resource.Id.Image).SetImageResource(item.ImageResourceId); return view; } }
GetView
メソッド内で、TableItem
のプロパティをそれぞれ割り当てます。
Activity で CustomAdapter を使う
ソースの List
を用意して先ほど作った CustomListAdapter(Activity context, List<TableItem> items)
をインスタンス化して ListView
の Adapter に指定します。
// ソースのListにアイテムを追加 tableItem.Insert(0, new TableItem() { Name = "item_1", Description = "Description_1", ImageResourceId = images[4] }); // CustomAdapterを作成して適用 var customAdapter = new CustomListAdapter(this, tableItem); listView.Adapter = customAdapter;
データの追加、削除は、ソースの List に対して行い、Adapter に変更を通知してあげると良いそうです。(@Santea3173 さん、ありがとう!!)
@ytabuchi アイテム追加して、AbsListView#InvalidateViews() か BaseAdapter#NotifyDataSetChanged() で更新されるかと思いますが、いかがでしょうか?
— サンテア@夏休みはなさそうです (@Santea3173) 2016年8月18日
ボタンをタップするとデータを追加したり削除したりする部分はこんな感じです。
var addButton = FindViewById<Button>(Resource.Id.customListViewAddButton); addButton.Click += (sender, e) => { var rdm = new Random(); // ソースのListにアイテムを追加し、Adapterに変更を通知して画面を更新させる tableItem.Insert(0, new TableItem() { Name = "item_" + rdm.Next(), Description = "Description_" + rdm.Next(), ImageResourceId = images[rdm.Next(0, 8)] // *1 }); customAdapter.NotifyDataSetChanged(); }; var deleteButton = FindViewById<Button>(Resource.Id.customListViewDeleteButton); deleteButton.Click += (sender, e) => { if (tableItem.Count > 0) { // ソースのListからアイテムを削除し、Adapterに変更を通知して画面を更新させる tableItem.Remove(tableItem[tableItem.Count - 1]); customAdapter.NotifyDataSetChanged(); } };
*1 ですが、Randomで参照するので作成した画像データを元に int[] に Resource.Drawable.ramen1 などを入れておいてます。
ListView もそんなに怖くないですね。
ちょっとビビっていましたが、Android の ListView は大丈夫そうです。次は CardView か RecyclerView とかにチャレンジしたいですね。
Xamarin 気になった方は
是非 ダウンロード して触ってみてください。Visual Studio 2015 をご利用の方は Update 3 にアップデートする際にカスタムインストールで Xamarin を追加しましょう。 学習用リソース や JXUG リンクページ に参考資料を纏めてますので併せてどうぞ。
Xamarin の導入支援サービスを始めました。ベースは基本的なアプリを一緒に作ることで Xamarin を使えるようになって頂く内容ですが、ご要望に応じて講習内容のカスタマイズも可能です。詳しくは田淵までお問い合わせください(^^)
Xamarin の情報が欲しい方はこのブログも購読いただいたり、私のTwitterアカウントをフォローいただいたりすると嬉しいです。
私が所属している エクセルソフト の宣伝を少しさせてください。弊社は開発者向けの様々なソフトウェアを扱っています。おなじみの ReSharper (JetBrains)、 や Atlassian の JIRA, Confluence、Office/PDF ファイルを .NET/Java で操作するライブラリ Aspose(アスポーズ)、Windows アプリ、Web ページ、iOS/Android アプリの UI テストができる TestComplete などお勧めです(^^) また、Visual Studio Professional/Enterprise with MSDN も販売してますし、日本で売っていない海外のソフトウェア、開発ツールなどを弊社経由で日本円で購入頂くことも可能です。ご興味あれば 弊社ページ を覗いてみてください。
以上です。