Quantcast
Channel: かずきのBlog@hatena
Viewing all articles
Browse latest Browse all 1387

Xamarin.Android + ReactivePropertyでListViewを使う

$
0
0

特にReactivePropertyでサポートはしてないので自前でやるっきゃないです!ということでこういうクラスを書いてみました。

ReadOnlyReactiveCollection型をIListAdapterに変換するコードです。

publicstaticclass ReadOnlyCollectionExtensions
{
    /// <summary>/// ReadOnlyReactiveCollectionをIListAdapterに変換する/// </summary>/// <typeparam name="T"></typeparam>/// <paramname="self"></param>/// <paramname="createRowView">行のデータを表示するためのViewを作る処理</param>/// <paramname="setRowData">行にデータを設定する処理</param>/// <returns></returns>publicstatic IListAdapter ToAdapter<T>(this ReadOnlyReactiveCollection<T> self, 
        Func<View> createRowView,
        Action<T, View> setRowData)
    {
        returnnew ReadOnlyReactiveCollectionAdapter<T>(self, createRowView, setRowData);
    }
}

/// <summary>/// ReadOnlyReactiveCollection用のAdapterクラス/// </summary>/// <typeparam name="T"></typeparam>class ReadOnlyReactiveCollectionAdapter<T> : BaseAdapter<T>
{
    // もとになるコレクションprivate ReadOnlyReactiveCollection<T> source;
    // 行のデータを表示するためのViewを作る処理private Func<View> createRowView;
    // 行にデータを設定する処理private Action<T, View> setRowData;

    public ReadOnlyReactiveCollectionAdapter(
        ReadOnlyReactiveCollection<T> source,
        Func<View> createRowView,
        Action<T, View> setRowData)
    {
        this.source = source;
        this.createRowView = createRowView;
        this.setRowData = setRowData;
    }

    publicoverride T this[int position]
    {
        get { return source[position]; }
    }

    publicoverrideint Count
    {
        get { returnthis.source.Count; }
    }

    publicoverridelong GetItemId(int position)
    {
        return position;
    }

    publicoverride View GetView(int position, View convertView, ViewGroup parent)
    {
        if (convertView == null)
        {
            convertView = this.createRowView();
        }
        this.setRowData(this[position], convertView);
        return convertView;
    }
}

使い方は簡単です。以下のようなコマンドを実行するとコレクションにデータを追加するだけのViewModelがあったとします。

publicclass MainActivityViewModel
{
    private ObservableCollection<string> source = new ObservableCollection<string> { "a", "b", "c" };
    public ReadOnlyReactiveCollection<string> Items { get; private set; }

    public ReactiveCommand AddItemCommand { get; private set; }

    public MainActivityViewModel()
    {
        this.Items = source.ToReadOnlyReactiveCollection();

        this.AddItemCommand = new ReactiveCommand();
        this.AddItemCommand.Subscribe(_ =>
        {
            this.source.Add("item" + DateTime.Now);
        });
    }
}

そして、ボタンとListViewを置いた画面でさくっと紐づけ。

[Activity(Label = "App1", MainLauncher = true, Icon = "@drawable/icon")]
publicclass MainActivity : Activity
{
    private MainActivityViewModel viewModel = new MainActivityViewModel();

    protectedoverridevoid OnCreate(Bundle bundle)
    {
        base.OnCreate(bundle);

        // Set our view from the "main" layout resource
        SetContentView(Resource.Layout.Main);

        this.FindViewById<Button>(Resource.Id.button1).Click += viewModel.AddItemCommand.ToEventHandler();

        var listView = this.FindViewById<ListView>(Resource.Id.listView1);
        listView.Adapter = viewModel.Items.ToAdapter(
            () => LayoutInflater.FromContext(this).Inflate(Resource.Layout.layout1, null),
            (x, v) => v.FindViewById<TextView>(Resource.Id.textView1).Text = x);
        this.viewModel.Items.CollectionChangedAsObservable().Subscribe(_ => listView.InvalidateViews());
    }
}

一応レイアウトファイルも

main.axml

<?xml version="1.0" encoding="utf-8"?><LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"android:orientation="vertical"android:layout_width="fill_parent"android:layout_height="fill_parent"><Buttonandroid:text="Button"android:layout_width="match_parent"android:layout_height="wrap_content"android:id="@+id/button1" /><ListViewandroid:minWidth="25px"android:minHeight="25px"android:layout_width="match_parent"android:layout_height="match_parent"android:id="@+id/listView1" /></LinearLayout>

layout1.axml

<?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"><ImageViewandroid:src="@android:drawable/ic_menu_gallery"android:layout_width="wrap_content"android:layout_height="match_parent"android:id="@+id/imageView1" /><TextViewandroid:text="Medium Text"android:textAppearance="?android:attr/textAppearanceMedium"android:layout_width="wrap_content"android:layout_height="match_parent"android:id="@+id/textView1" /></LinearLayout>

Viewing all articles
Browse latest Browse all 1387

Trending Articles



<script src="https://jsc.adskeeper.com/r/s/rssing.com.1596347.js" async> </script>