Xamarin逆引きTips

Xamarin逆引きTips

MvvmCrossで画像をバインディングするには?

2015年8月5日

MvvmCrossでのiOS/Androidアプリ開発において、画像のURLをViewへバインディングできるMvxImageViewの使い方を説明する。

  • このエントリーをはてなブックマークに追加

 MvvmCrossのiOS/Androidアプリ開発では、MvxImageViewへ画像のURLをバインディングすることで画像のダウンロードと表示ができる。

 今回は、MvxImageViewへバインディングして画像を表示する方法を解説する*1

  • *1 なお、本TipsはMac OS X(10.10.4)+Xamarin Studio(5.9.4)+MvvmCross(3.5.1)で動作を確認している。

MvxImageView

 MvvmCrossに標準で含まれているMvxImageViewクラスは、任意の画像をバインディング可能なViewクラスである。iOSではUIImageViewクラスを、AndroidではImageViewクラスを継承しており、画面へ配置することが可能だ。

 MvxImageViewクラスのImageUrlプロパティには、ローカルの画像リソース名または画像URLを指定する。例えば、ファイル名が「sample.png」である画像リソースをアプリが保持しているとき、ImageUrlプロパティへ文字列「res:sample」を設定すると、それぞれのプラットフォームのリソースから「sample.png」を取得して表示する。このように、リソース名の先頭に「res:」を付与したものはローカルリソースと見なされる。iOSであればXCAssetsの仕組みに従って画像が選択され、AndroidであればDrawableフォルダーの仕組みに従って画像が選択される*2

 ImageUrlプロパティへHTTPやHTTPSの画像URLが指定されると、MvxImageViewクラスが画面へ表示されるタイミングで画像のダウンロードを開始し、ダウンロードが完了したら画面へ表示される。MvxImageViewクラスにはDefaultImagePathプロパティとErrorImagePathプロパティがあり、DefaultImagePathプロパティは、画像のダウンロードが完了するまでの間に表示する画像リソースを指定し、ErrorImagePathプロパティは画像のダウンロードが失敗したときに表示する画像リソースを指定する。DefaultImagePathErrorImagePathにはローカルの画像リソースのみ指定することができる。

プロパティ説明
ImageUrl 画像URLまたはローカル画像リソース名
DefaultImagePath ローカル画像リソース名
ErrorImagePath ローカル画像リソース名
表1 MvxImageViewの画像リソース指定プロパティ一覧

 MvxImageViewクラスの画像のダウンロードにはDownloadCacheプラグインが使用されており、画像のメモリキャッシュやストレージキャッシュもDownloadCacheプラグインの設定に従って動作する。

実装方針

 それでは、実際にMvxImageViewクラスを用いた画像表示を実装してみよう。

 今回はDefaultImagePathプロパティとImageUrlプロパティの動作を確認する。画面に2つのボタンとMvxImageViewを設置し、ボタンによってImageUrlプロパティの値を変化させることでMvxImageViewの動作を確認する。

 また、DefaultImagePathプロパティへ設定する画像として、次の「placeholder.png」画像リソースを使用する。

図1 DefaultImagePathに設定するplaceholder.png画像リソース
図1 DefaultImagePathに設定するplaceholder.png画像リソース

プロジェクトの作成

 「Tips: MvvmCrossのプロジェクトをセットアップするには?」の手順に従い、MvvmCrossプロジェクトを作成する。ソリューション名は「CrossImageSample」と設定する。

プラグインの追加

 まずは、MvxImageViewクラスの動作に必要なプラグインをNuGetから追加する。Coreプロジェクト、Touchプロジェクト、Droidプロジェクト全てに、以下のNuGetパッケージを取得する。Xamarin Studioでは[ソリューション]ビューのプロジェクトを右クリックし、(それにより表示されるコンテキストメニューの)[追加]-[Add NuGet Packages]から取得する。

Coreの実装

 CoreプロジェクトのViewModelクラスを実装する。ViewModelsフォルダーのFirstViewModel.csファイルを次のように実装する。

C#
using Cirrious.MvvmCross.ViewModels;

namespace CrossImageSample.Core.ViewModels
{
  public class FirstViewModel : MvxViewModel {
    IMvxCommand _reset;
    public IMvxCommand Reset {
      get {
        return _reset ?? (_reset = new MvxCommand(() => {
          // 1
          ImageUrl = null;
        }));
      }
    }

    IMvxCommand _getImage;
    public IMvxCommand GetImage {
      get {
        return _getImage ?? (_getImage = new MvxCommand(() => {
          // 2
          ImageUrl = "http://re.buildinsider.net/img/logo-fb.png";
        }));
      }
    }

    string _imageUrl = null;
    public string ImageUrl { // 3
      get { return _imageUrl; }
      set {
        _imageUrl = value;
        RaisePropertyChanged (() => ImageUrl);
      }
    }
  }
}
FirstViewModel.csの実装

 1は画像URLにnullを設定することで画像表示をリセットするコマンドを実装している。

 2は画像URLに「http://re.buildinsider.net/img/logo-fb.png」を設定するコマンドを実装している。

 3MvxImageViewへバインドするプロパティを定義している。初期値はnullとしている。

Touchプロジェクトの実装

 Touchプロジェクトにplaceholder.png画像リソースを設置する。Xamarin Studioでは[ソリューション]ビューから[Resources]フォルダ内の[Images.xcassets]を右クリックし、[追加]ー[New Image Set]によってImages.xcassetsフォルダー内へ「Image.imageset」フォルダーを作成する。作成した「Image.imageset」フォルダーの名前を「placeholder.imageset」へ変更する。「Images.xcassets」をダブルクリックで開くと「placeholder」項目が追加されているので、Finderから「placeholder.png」ファイルをiPhone 1xの項目へドラッグ&ドロップする*3

  • *3 Xamarin Studioではなく、XcodeからImages.xcassetsを開き、Xcode上でXCAssetsの編集をしても構わない
図2 Xamarin StudioでのiOS画像リソースの追加

 TouchプロジェクトのViewクラスを実装する。ViewsフォルダーのFirstView.csファイルを次のように実装する。

C#
using Cirrious.MvvmCross.Binding.BindingContext;
using Cirrious.MvvmCross.Touch.Views;
using CoreGraphics;
using Foundation;
using ObjCRuntime;
using UIKit;
using Cirrious.MvvmCross.Binding.Touch.Views;
 
namespace CrossImageSample.Touch.Views
{
  [Register("FirstView")]
  public class FirstView : MvxViewController
  {
    public override void ViewDidLoad()
    {
      View = new UIView { BackgroundColor = UIColor.White };
      base.ViewDidLoad();
 
      // ios7 layout
      if (RespondsToSelector(new Selector("edgesForExtendedLayout")))
      {
         EdgesForExtendedLayout = UIRectEdge.None;
      }
 
      // 1
      var resetButton = new UIButton (UIButtonType.System);
      resetButton.Frame = new CGRect (10, 10, 100, 40);
      resetButton.SetTitle("Reset", UIControlState.Normal);
      Add (resetButton);
      var getButton = new UIButton (UIButtonType.System);
      getButton.Frame = new CGRect (10, 50, 100, 40);
      getButton.SetTitle("Get Image", UIControlState.Normal);
      Add (getButton);
      var imageView = new MvxImageView (new CGRect (10, 100, 200, 200));
      imageView.DefaultImagePath = "res:placeholder";
      imageView.ContentMode = UIViewContentMode.ScaleAspectFit;
      Add (imageView);
 
      // 2
      var set = this.CreateBindingSet<FirstView, Core.ViewModels.FirstViewModel>();
      set.Bind (resetButton).To (vm => vm.Reset);
      set.Bind (getButton).To (vm => vm.GetImage);
      set.Bind (imageView).For (v => v.ImageUrl).To (vm => vm.ImageUrl);
      set.Apply();
    }
  }
}
TouchプロジェクトのFirstView.csの実装

 1で画面レイアウトを作成している。imageViewDefaultImagePathプロパティにローカルリソースの「placeholder」画像リソースを設定している。UIImageクラスのContentModeプロパティを設定し、画像がViewのサイズに収まるようにしている。

 2でバインディングを設定している。imageViewImageUrlプロパティがバインディングされている。

Droidプロジェクトの実装

 Droidプロジェクトにplaceholder.png画像リソースを追加する。具体的には図2の手順で、[Resources]ー[drawable-mdpi]フォルダーへplaceholder.png画像リソースを設置する。

図2 Droidプロジェクトへの画像リソースの追加
図2 Droidプロジェクトへの画像リソースの追加

 Droidプロジェクトのレイアウトを実装する。[Resources]ー[layout]フォルダー内のFirstView.axmlファイルを次のように実装する。

XML
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
  xmlns:local="http://schemas.android.com/apk/res-auto"
  android:orientation="vertical"
  android:layout_width="match_parent"
  android:layout_height="match_parent">
  <Button
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:text="Reset"
    local:MvxBind="Click Reset" />
  <Button
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:text="Get Image"
    local:MvxBind="Click GetImage" />
  <!-- 1 -->
  <Mvx.MvxImageView
    android:id="@+id/image"
    android:layout_width="200dp"
    android:layout_height="200dp"
    android:scaleType="fitCenter"
    local:MvxBind="ImageUrl ImageUrl" />
</LinearLayout>
FirstView.axmlの実装

 1ではMvxImageViewを設置している。MvxImageViewはレイアウトXMLファイル内ではタグ名にMvx.MvxImageViewと指定する。MvxImageViewクラスのImageUrlプロパティをバインディング設定している。

 次に、Viewクラスを実装する。[Views]フォルダー内のFirstView.csファイルを次のように実装する。

C#
using Android.App;
using Android.OS;
using Cirrious.MvvmCross.Droid.Views;
using Cirrious.MvvmCross.Binding.Droid.Views;

namespace CrossImageSample.Droid.Views
{
  [Activity(Label = "View for FirstViewModel")]
  public class FirstView : MvxActivity
  {
    protected override void OnCreate(Bundle bundle)
    {
      base.OnCreate(bundle);
      SetContentView(Resource.Layout.FirstView);

      // 1
      MvxImageView imageView = FindViewById<MvxImageView> (Resource.Id.image);
      imageView.DefaultImagePath = "res:placeholder";
    }
  }
}
DroidプロジェクトのFirstView.csの実装

 1で、imageViewDefaultImagePathプロパティを設定する。DefaultImagePathプロパティにはローカルのplaceholder画像リソースを指定している。レイアウトXMLファイルではDefaultImagePathプロパティを設定することはできないため、FirstViewクラスを実装している。

実行結果

 Touchプロジェクト、Droidプロジェクトを実行すると、それぞれ次のような動作結果となる。

図4 Touchプロジェクトの動作
図5 Droidプロジェクトの動作

 起動後はMvxImageViewにはplaceholder画像が表示されており、[Get Image]ボタンをタップすると、画像をダウンロードした後、その画像を表示する。[Reset]ボタンをタップするとplaceholder画像の表示に戻る。さらに、2回目以降の[Get Image]ボタンタップでは、画像がキャッシュされているため、ダウンロードをスキップして指定された画像を表示する。

※以下では、本稿の前後を合わせて5回分(第55回~第59回)のみ表示しています。
 連載の全タイトルを参照するには、[この記事の連載 INDEX]を参照してください。

55. MvvmCrossでカスタムコントロールをTwo-Wayバインディングに対応させるには?

MvvmCrossでのiOS/Androidアプリ開発において、カスタムビュークラスをTwo-Wayバインディングに対応させる方法を解説する。

56. Xamarin.FormsでAzureモバイルサービスによるToDoアプリを作成するには?

ひな型プロジェクトが用意されているXamarin.iOSやXamarin.Androidではなく、Xamarin.FormsからAzureモバイルサービスを活用する基本的な方法を、簡単なToDoアプリを題材に解説する。

57. 【現在、表示中】≫ MvvmCrossで画像をバインディングするには?

MvvmCrossでのiOS/Androidアプリ開発において、画像のURLをViewへバインディングできるMvxImageViewの使い方を説明する。

58. MvvmCrossで文字列をローカライズ(多言語化)するには?

MvvmCrossでのiOS/Androidアプリ開発において、ViewModelの文字列リソースを多言語化してローカライズする方法を解説する。

59. MvvmCrossでViewModelからViewにイベントを通知するには?(Messengerパターン)

MvvmCrossでのiOS/Androidアプリ開発において、ViewModelからViewにイベントを通知するMessengerパターンの実装方法を紹介する。

イベント情報(メディアスポンサーです)

Twitterでつぶやこう!


Build Insider賛同企業・団体

Build Insiderは、以下の企業・団体の支援を受けて活動しています(募集概要)。

ゴールドレベル

  • 日本マイクロソフト株式会社
  • グレープシティ株式会社