Cでの単純なiOSアプリケーションのMvvmCross#

こんにちは。 .NET(以下、C#と呼びます)のクロスプラットフォームアプリケーションの開発者は、おそらくMvvmCrossの存在を知っています。 優れた製品。その主な欠点は、ドキュメントが非常に少ないことです。 ロシア語では、それもほとんど存在しません。 ここでは、MvvmCross iOSに基づいたiOS用のメニューを備えた単純なアプリケーションの構造の概要を説明します。



Appleの実際のハードウェアを持っていない場合は、何もできないので、すぐに注意してください。 プロジェクトのアセンブリとデバッグは、実際のAppleデバイスでのみ可能です。 Windowsで作業できますが。 すなわち USBデバッグによるAndroidアプリケーションの実行方法のおおよその方法。 これがこのオフィスのポリシーです。



このテキストを書いている時点では、MvvmCrossは.NETStandardをサポートしていないため、2017ではなくVisualStudio 2015でプロジェクトを作成する必要があります。完成したプロジェクトは2017年編集できます 。この問題を回避できるようになりました。 指示 さらに、Xamarinをスタジオにインストールする必要があります。



すべてのコード例は最大限に簡略化されており、おそらく一部の場所ではイデオロギー的に正確ではありませんが、機能しています。 たとえば、テーブルの形式でメニューを作成し、それにデータソースを接続することをお勧めします。



MvvmCrossを接続します。「NuGetパッケージの管理」を通じて、MvvmCross、MvvmCross.iOS.Support、MvvmCross.iOS.Support.XamarinSidebar、SidebarNavigationを配置します。 パッケージのセットはバージョンに依存します。ここではMvvmCross 5.12についてです。



そのため、まず、「iOS-Universal-empty application」のような新しいプロジェクトを作成する必要があります。 iOSTestと呼びましょう。 プロジェクトフォルダーに異なるファイルが表示されます。 ここでのメインはMain.csファイルです。 アプリケーションを実行するのはこのファイルです。 その構造と役割は非常に単純です。 彼は、Main.csのすぐ隣にあるAppDelegate.csを起動します。



AppDelegate.csはメインウィンドウを作成し、制御をさらに転送します。 これを行うには、オーバーロードされたFinishedLaunching関数を次のように書き換える必要があります。



Appdelegate.cs
public override bool FinishedLaunching(UIApplication app, NSDictionary options) { Window = new UIWindow(UIScreen.MainScreen.Bounds); var setup = new Setup(this, Window); setup.Initialize(); var startup = Mvx.Resolve<IMvxAppStart>(); startup.Start(); Window.MakeKeyAndVisible(); return true; }
      
      







さらに、AppDelegateの継承元のクラスを変更する必要があります。 クラス宣言は次のようになります。



 public class AppDelegate : MvxApplicationDelegate
      
      





残りはそのままにします。



これをすべて機能させるには、Setup.csファイルをプロジェクトに追加します。



コードは次のようなものです。



Setup.cs
 using MvvmCross.Core.ViewModels; using MvvmCross.iOS.Platform; using MvvmCross.iOS.Views.Presenters; using MvvmCross.iOS.Support.XamarinSidebar; using MvvmCross.Platform.Platform; using UIKit; namespace iOSTest { public class Setup : MvxIosSetup { public Setup(MvxApplicationDelegate applicationDelegate, UIWindow window) : base(applicationDelegate, window) { } public Setup(MvxApplicationDelegate applicationDelegate, IMvxIosViewPresenter presenter) : base(applicationDelegate, presenter) { } protected override IMvxApplication CreateApp() { return new App(); } protected override IMvxIosViewPresenter CreatePresenter() { return new MvxSidebarPresenter((MvxApplicationDelegate)ApplicationDelegate, Window); } } }
      
      







ここでの主なものはCreateApp()です。 App()がまだ存在しないため、スタジオはエラーを表示しています。



ここで、ソリューションに新しいプロジェクトを作成する必要があります。ViewModelsは、MVVMパラダイムに従って配置されます。 このプロジェクトはポータブルまたは.NETStandardである必要がありますが、現時点ではMvvmCrossはPCLプロジェクトのみです。 そのプロジェクトの「ドラフト」がある場合は、2017年のスタジオにコピーするだけです。 彼は問題なく働くでしょう。 これを「コア」と呼び、NuGet MvvmCrossを介して接続し、ルートにApp.csファイルを作成します。 新しいプロジェクトをリンクとして最初のプロジェクトに接続すると、Setup.csのエラーが消えます。



App.csコンテンツは非常に原始的です:



App.cs
 using Core.ViewModels; using MvvmCross.Platform.IoC; namespace Core { public class App : MvvmCross.Core.ViewModels.MvxApplication { public override void Initialize() { CreatableTypes() .EndingWith("Service") .AsInterfaces() .RegisterAsLazySingleton(); RegisterAppStart<StartViewModel>(); } } }
      
      







RegisterAppStart(); 最終的に最初の実際に動作するコードに到達します。 推測するのは難しいことではないので、ここで「StartViewModel」が起動​​されます。以前のものはすべて起動の準備でした。 CoreプロジェクトにViewModelsフォルダーを作成し、その中にStartViewModel.csファイルを作成します。



StartViewModel.cs
 using MvvmCross.Core.ViewModels; namespace Core.ViewModels { public class StartViewModel: MvxViewModel { public void ShowMainView() { ShowViewModel<MainViewModel>(); } } }
      
      







このViewModelでできることは、MainViewModelを起動することだけです。 ここでは、そのような敷設が冗長に見えることに注意する必要があります。すぐにMainViewModelを起動しないのはなぜですか。 MvvmCrossの一部のバージョンまでは変更されていましたが、現在は何かが変更されており、MainViewModelをすぐに起動してもメニューは表示されません。 おそらくこれはバグであり、修正されるでしょう。 ただし、現在中間クラスを使用していない場合、メニューは左側ではなく右側に表示されます。設定のように、画面の端を引くだけで表示できます。メニューを呼び出すボタンはありません(右側の画面外にあると思われます)。



MainViewModel.cs:



MainViewModel.cs
 using MvvmCross.Core.ViewModels; namespace Core.ViewModels { public class MainViewModel : MvxViewModel { public void ShowMenu() { ShowViewModel<MenuViewModel>(); } } }
      
      







ここではすべてが簡単です。 モデルは本質的に空であり、できることはメニューを表示することだけです。 実際のプロジェクトでは、必要に応じてさまざまな機能を使用できます。



MainViewModel.csの横に、MenuViewModel.csを作成して、メニューの動作を記述します。



MenuViewModel.cs
 using System; using System.Collections.Generic; using Core.Models; using MvvmCross.Core.ViewModels; namespace Core.ViewModels { public class MenuViewModel : MvxViewModel { public List<MenuModel> MenuItems { get; } public MenuViewModel() { MenuItems = new List<MenuModel> { new MenuModel {Title = "Settings", Navigate = NavigateCommandSettings}, new MenuModel {Title = "About", Navigate = NavigateCommandAbout} }; } private MvxCommand<Type> _navigateCommandSettings; public MvxCommand<Type> NavigateCommandSettings { get { _navigateCommandSettings = _navigateCommandSettings ?? new MvxCommand<Type>((vm) => { ShowViewModel<SettingsViewModel>(); }); return _navigateCommandSettings; } } private MvxCommand<Type> _navigateCommandAbout; public MvxCommand<Type> NavigateCommandAbout { get { _navigateCommandAbout = _navigateCommandAbout ?? new MvxCommand<Type>((vm) => { ShowViewModel<AboutViewModel>(); }); return _navigateCommandAbout; } } } }
      
      







ご覧のとおり、メニューには2行しかありません。



次に、メニューのモデルを作成します。 すなわち 文字列のテンプレート。 CoreプロジェクトのModels / MenuModel.csファイル:



MenuModel.cs
 using System; using MvvmCross.Core.ViewModels; namespace Core.Models { public class MenuModel { public String Title { get; set; } public MvxCommand<Type> Navigate { get; set; } } }
      
      







個々のメニュー行について説明します。 行のテキストと実行するコマンド。



メニュー項目から移動するには、さらに2つのほぼ同一のViewModelを作成します。 違いは名前だけです。 AboutViewModel.csおよびSettingsViewModel.cs



AboutViewModel.cs
 using MvvmCross.Core.ViewModels; namespace Core.ViewModels { public class AboutViewModel : MvxViewModel { } }
      
      







実際のコードでは、このViewModelにアクセスするときに実行される関数を配置する必要があります。



ここでiOSTestプロジェクトに戻り、MvvmCrossの魔法に取り組み始めます。 実際には、ViewとViewModel間の接続はMvvmCross内のどこかで発生し、明示的には表示されません。 コードはViewModelを呼び出し、Viewが表示されますが、コードにどのViewを表示するかは示されていません。



私が理解しているように、各ビューはその名前だけでそのViewModelに関連付けられています。 ビューの宣言にはフィードバックが存在します。 一般に、すべてはなんとなく曖昧です。



iOSTestプロジェクトにViewsフォルダを作成し、その中にすべてのViewModelsのビューを作成します:MainView、MenuView、AboutView、SettingsView。 残念ながら、VisualStudioはビューを作成する最良の方法ではありません。 Xamarin iOS DesignerまたはXcode Interface Builderを使用する必要があります。 詳細はこちらをご覧ください: リンクこれにより、美しいビューを作成できます。



しかし、次のようにします。MainView.cs、MenuView.sc、AboutView.cs、SettingsView.csの各ファイルを通常のクラスとして作成し、それらの表現をプログラムで記述します。 あまり美しくありませんが、シンプルです。



MainView.cs
 using Core.ViewModels; using CoreGraphics; using MvvmCross.iOS.Support.XamarinSidebar; using MvvmCross.iOS.Views; using UIKit; namespace iOSTest.Views { [MvxSidebarPresentation(MvxPanelEnum.Center, MvxPanelHintType.ResetRoot, true)] public class MainView : MvxViewController<MainViewModel> { public override void ViewDidLoad() { base.ViewDidLoad(); View.BackgroundColor = UIColor.LightGray; var label = new UILabel { Frame = new CGRect(10, 60, 200, 50), TextColor = UIColor.Magenta, Font = UIFont.FromName("Helvetica-Bold", 20f), Text = "MainWiew" }; Add(label); } } }
      
      







クラスを宣言する前に、属性に注意してください。 これは、このビューにバインドするメニューです。



AboutView.cs(SettingsViewと同様)



AboutView.cs
 using Core.ViewModels; using CoreGraphics; using MvvmCross.iOS.Support.XamarinSidebar; using MvvmCross.iOS.Views; using UIKit; namespace iOSTest.Views { [MvxSidebarPresentation(MvxPanelEnum.Center, MvxPanelHintType.PushPanel, true)] public class AboutView : MvxViewController<AboutViewModel> { public override void ViewDidLoad() { base.ViewDidLoad(); View.BackgroundColor = UIColor.LightGray; var label = new UILabel { Frame = new CGRect(10, 60, 200, 50), TextColor = UIColor.Magenta, Font = UIFont.FromName("Helvetica-Bold", 20f), Text = "AboutView" }; Add(label); } } }
      
      







ここで、属性は少し異なります。 「ResetRoot」の代わりに「PushPanel」を使用すると、メニュー呼び出しボタンの代わりに「<Back」ボタンが表示され、前のウィンドウに戻ります。 つまり、すべてのウィンドウにメニューボタンを配置する場合は、「ResetRoot」と記述します



最後に、MenuView.cs:



MenuView.cs
 using System.Globalization; using Core.ViewModels; using CoreGraphics; using MvvmCross.iOS.Support.XamarinSidebar; using MvvmCross.iOS.Support.XamarinSidebar.Views; using MvvmCross.iOS.Views; using MvvmCross.Platform; using UIKit; namespace iOSTest.Views { [MvxSidebarPresentation(MvxPanelEnum.Left, MvxPanelHintType.PushPanel, false)] public class MenuView : MvxViewController<MenuViewModel>, IMvxSidebarMenu { private CGColor _borderColor = new CGColor(45, 177, 128); private readonly UIColor _backgroundColor = UIColor.FromRGB(140, 176, 116); private readonly UIColor _textColor = UIColor.Black; public override void ViewDidLoad() { base.ViewDidLoad(); View.BackgroundColor = _backgroundColor; EdgesForExtendedLayout = UIRectEdge.None; var label = new UILabel { Frame = new CGRect(10f, 30f, MenuWidth, 20f), TextColor = _textColor, Font = UIFont.FromName("Helvetica", 20f), Text = "", TextAlignment = UITextAlignment.Center }; Add(label); var i = 0; foreach (var item in ViewModel.MenuItems) { var itemButton = new UIButton(); itemButton.Frame = new CGRect(10, 100+i, MenuWidth, 20); itemButton.SetTitle(item.Title, UIControlState.Normal); itemButton.TitleLabel.Font = UIFont.FromName("Helvetica", 20f); itemButton.TitleLabel.TextColor = _textColor; itemButton.BackgroundColor = _backgroundColor; itemButton.TouchUpInside += delegate { item.Navigate.Execute(); Mvx.Resolve<IMvxSidebarViewController>().CloseMenu(); }; i += 30; Add(itemButton); } } public void MenuWillOpen(){} public void MenuDidOpen(){} public void MenuWillClose(){} public void MenuDidClose(){} private int MaxMenuWidth = 300; private int MinSpaceRightOfTheMenu = 55; public bool AnimateMenu => true; public bool DisablePanGesture => false; public float DarkOverlayAlpha => 0; public bool HasDarkOverlay => false; public bool HasShadowing => true; public UIImage MenuButtonImage => new UIImage("menu.png"); public int MenuWidth => UserInterfaceIdiomIsPhone ? int.Parse(UIScreen.MainScreen.Bounds.Width.ToString(CultureInfo.InvariantCulture)) - MinSpaceRightOfTheMenu : MaxMenuWidth; public bool ReopenOnRotate => true; private bool UserInterfaceIdiomIsPhone => UIDevice.CurrentDevice.UserInterfaceIdiom == UIUserInterfaceIdiom.Phone; } }
      
      







属性が再びわずかに変更され、メニューが左側にあることは明らかです。 メニューアイコンは、「menu.png」ファイルにあります。このファイルは、すべてのiOSルールに従って、リソースフォルダーに配置する必要があり、できれば3つの解像度(サイズ)で配置する必要があります。



IMvxSidebarMenuインターフェイスの実装を放棄すると、コードはほぼ2倍に削減できますが、メニューアイコンはありません。 「メニュー」という碑文があります。



それだけです。







プロジェクト全体はここで見ることができます: github




All Articles