Xamarin.iOS でのコードでの iOS ユーザー インターフェイスの作成
iOS アプリのユーザー インターフェイスは店舗の正面のようなものです。アプリケーションは、通常、1 つのウィンドウを取得しますが、そのウィンドウいっぱいに必要な数のオブジェクトを表示し、アプリが表示したい内容に応じてオブジェクトの配置を変更することもできます。 このシナリオのオブジェクト (ユーザーに表示される物事) はビューと呼ばれます。 アプリケーションで 1 つの画面をビルドするには、コンテンツ ビュー階層にビューが相互に積み重ねられ、階層が単一のビュー コントローラーによって管理されます。 複数の画面を持つアプリケーションには、複数のコンテンツ ビュー階層、それぞれに独自のビュー コントローラー、およびウィンドウ内のアプリケーションの場所のビューがあり、ユーザーに表示される画面に基づいて異なるコンテンツ ビュー階層を作成します。
次の図は、デバイスの画面にユーザー インターフェイスを表示するウィンドウ、ビュー、サブビュー、およびビュー コントローラー間の関係を示しています。
これらのビュー階層は Xcode の Interface Builder を使用して構築できますが、コード内で全ての操作を行う方法を基本的に理解することをお勧めします。 この記事では、コードのみのユーザー インターフェイス開発に着手して作業を進めるための基本的なポイントについて説明します。
コードのみのプロジェクトの作成
iOS の空のプロジェクト テンプレート
まず、次に示すように、[ファイル] > [新しいプロジェクト] > [Visual C#] > [iPhone および iPad] > [iOS App (Xamarin)] プロジェクトを使用して、Visual Studio で iOS プロジェクトを作成します。
次に、[空のアプリ] プロジェクト テンプレートを選択します。
空のプロジェクト テンプレートは、プロジェクトに 4 つのファイルを追加します。
- AppDelegate.cs - iOS からのアプリケーション イベントを処理するために使用される、
UIApplicationDelegate
サブクラスAppDelegate
が含まれています。 アプリケーション ウィンドウは、AppDelegate
のFinishedLaunching
メソッドに作成されます。 - Main.cs -
AppDelegate
のクラスを指定するアプリケーションのエントリ ポイントを保存します。 - Info.plist - アプリケーション構成情報を含むプロパティ リスト ファイル。
- Entitlements.plist – アプリケーションの機能とアクセス許可に関する情報を含むプロパティ リスト ファイル。
iOS アプリケーションは、MVC パターンを使用して構築されます。 アプリケーションが表示する最初の画面は、ウィンドウのルート ビュー コントローラーから作成されます。 MVC パターン自体の詳細については、「Hello、iOS マルチスクリーン」ガイドを参照してください。
テンプレートによって追加された AppDelegate
の実装により、アプリケーション ウィンドウが作成されます。このウィンドウは、すべての iOS アプリケーションに対して 1 つだけ存在し、次のコードで表示されます。
public class AppDelegate : UIApplicationDelegate
{
public override UIWindow Window
{
get;
set;
}
public override bool FinishedLaunching(UIApplication app, NSDictionary options)
{
// create a new window instance based on the screen size
Window = new UIWindow(UIScreen.MainScreen.Bounds);
// make the window visible
Window.MakeKeyAndVisible();
return true;
}
}
このアプリケーションをこの状態で実行すると、Application windows are expected to have a root view controller at the end of application launch
という例外がスローされる可能性があります。 コントローラーを追加し、それをアプリのルート ビュー コントローラーにしましょう。
コントローラーを追加する
アプリには多数のビュー コントローラーを含めることができますが、すべてのビュー コントローラーを制御するための 1 つのルート ビュー コントローラーが必要です。 UIViewController
インスタンスを作成し、Window.RootViewController
プロパティに設定して、コントローラーをウィンドウに追加します。
public class AppDelegate : UIApplicationDelegate
{
// class-level declarations
public override UIWindow Window
{
get;
set;
}
public override bool FinishedLaunching(UIApplication application, NSDictionary launchOptions)
{
// create a new window instance based on the screen size
Window = new UIWindow(UIScreen.MainScreen.Bounds);
var controller = new UIViewController();
controller.View.BackgroundColor = UIColor.LightGray;
Window.RootViewController = controller;
// make the window visible
Window.MakeKeyAndVisible();
return true;
}
}
すべてのコントローラーには、View
プロパティからアクセスできるビューが関連付けられています。 上記のコードでは、ビューの BackgroundColor
プロパティが UIColor.LightGray
に変更され、表示されるようになります。
UIKit のコントローラーや自分で記述したコントローラーなど、任意の UIViewController
サブクラスをこの方法で RootViewController
として設定することもできます。 たとえば、次のコードは、RootViewController
として UINavigationController
を追加します。
public class AppDelegate : UIApplicationDelegate
{
// class-level declarations
public override UIWindow Window
{
get;
set;
}
public override bool FinishedLaunching(UIApplication application, NSDictionary launchOptions)
{
// create a new window instance based on the screen size
Window = new UIWindow(UIScreen.MainScreen.Bounds);
var controller = new UIViewController();
controller.View.BackgroundColor = UIColor.LightGray;
controller.Title = "My Controller";
var navController = new UINavigationController(controller);
Window.RootViewController = navController;
// make the window visible
Window.MakeKeyAndVisible();
return true;
}
}
これにより、次に示すように、ナビゲーション コントローラー内に入れ子になったコントローラーが生成されます。
ビュー コントローラーの作成
ウィンドウの RootViewController
としてコントローラーを追加する方法を見てきたので、コードでカスタム ビュー コントローラーを作成する方法を見てみましょう。
次に示すように、CustomViewController
という名前の新しいクラスを追加します。
このクラスは、次に示すように、UIKit
名前空間の UIViewController
から継承しています。
using System;
using UIKit;
namespace CodeOnlyDemo
{
class CustomViewController : UIViewController
{
}
}
ビューの初期化
UIViewController
には、View コントローラーが最初にメモリに読み込まれるときに呼び出される ViewDidLoad
と呼ばれるメソッドが含まれています。 これは、ビューのプロパティの設定など、ビューの初期化を行うのに適した場所です。
たとえば、次のコードは、ボタンが押されたときにナビゲーション スタックに新しいビュー コントローラーをプッシュするボタンとイベント ハンドラーを追加します。
using System;
using CoreGraphics;
using UIKit;
namespace CodyOnlyDemo
{
public class CustomViewController : UIViewController
{
public CustomViewController ()
{
}
public override void ViewDidLoad ()
{
base.ViewDidLoad ();
View.BackgroundColor = UIColor.White;
Title = "My Custom View Controller";
var btn = UIButton.FromType (UIButtonType.System);
btn.Frame = new CGRect (20, 200, 280, 44);
btn.SetTitle ("Click Me", UIControlState.Normal);
var user = new UIViewController ();
user.View.BackgroundColor = UIColor.Magenta;
btn.TouchUpInside += (sender, e) => {
this.NavigationController.PushViewController (user, true);
};
View.AddSubview (btn);
}
}
}
このコントローラーをアプリケーションに読み込み、簡単なナビゲーションを例示するために、CustomViewController
の新しいインスタンスを作成します。 新しいナビゲーション コントローラーを作成し、ビュー コントローラー インスタンスを渡し、前と同様に新しいナビゲーション コントローラーを AppDelegate
のウィンドウの RootViewController
に設定します。
var cvc = new CustomViewController ();
var navController = new UINavigationController (cvc);
Window.RootViewController = navController;
アプリケーションが読み込まれると、CustomViewController
がナビゲーション コントローラー内に読み込まれます。
ボタンをクリックすると、新しいビュー コントローラーがナビゲーション スタックに "プッシュ" されます。
ビュー階層の構築
上記の例では、ビュー コントローラーにボタンを追加して、コード内にユーザー インターフェイスを作成し始めました。
iOS ユーザー インターフェイスは、ビュー階層で構成されます。 ラベル、ボタン、スライダーなどの追加のビューは、親ビューのサブビューとして追加されます。
例として、CustomViewController
を編集してユーザーがユーザー名とパスワードを入力できるログイン画面を作成しましょう。 画面は、2 つのテキスト フィールドとボタンで構成されます。
テキスト フィールドの追加
最初に、[ビューの初期化] セクションで追加したボタンとイベント ハンドラーを削除します。
次に示すように、UITextField
を作成して初期化し、ビュー階層に追加することで、ユーザー名のコントロールを追加します。
class CustomViewController : UIViewController
{
UITextField usernameField;
public override void ViewDidLoad()
{
base.ViewDidLoad();
View.BackgroundColor = UIColor.Gray;
nfloat h = 31.0f;
nfloat w = View.Bounds.Width;
usernameField = new UITextField
{
Placeholder = "Enter your username",
BorderStyle = UITextBorderStyle.RoundedRect,
Frame = new CGRect(10, 82, w - 20, h)
};
View.AddSubview(usernameField);
}
}
UITextField
を作成するときに、Frame
プロパティを設定して、その場所とサイズを定義します。 iOS では、0,0 座標は左上にあり、+x は右方向、+y は下方向になります。 Frame
を他のいくつかのプロパティと共に設定した後、View.AddSubview
を呼び出してビュー階層に UITextField
を追加します。 これにより、usernameField
は、View
プロパティが参照する UIView
インスタンスのサブビューになります。 サブビューは、親ビューより高い z オーダーで追加されるため、画面上の親ビューの前面に表示されます。
UITextField
が含まれているアプリケーションを次に示します。
次に示すように、パスワードの UITextField
を同様の方法で追加できます。しかし今回は SecureTextEntry
プロパティを true に設定します。
public class CustomViewController : UIViewController
{
UITextField usernameField, passwordField;
public override void ViewDidLoad()
{
// keep the code the username UITextField
passwordField = new UITextField
{
Placeholder = "Enter your password",
BorderStyle = UITextBorderStyle.RoundedRect,
Frame = new CGRect(10, 114, w - 20, h),
SecureTextEntry = true
};
View.AddSubview(usernameField);
View.AddSubview(passwordField);
}
}
SecureTextEntry = true
を設定すると、次に示すように、ユーザーが UITextField
に入力したテキストが非表示になります。
ボタンの追加
次に、ユーザーがユーザー名とパスワードを送信できるようにボタンを追加します。 ボタンは、他のコントロールと同様、親ビューの AddSubview
メソッドに引数として渡すことによってビュー階層に追加されます。
次のコードは、ボタンを追加し、TouchUpInside
イベントのイベント ハンドラーを登録します。
var submitButton = UIButton.FromType (UIButtonType.RoundedRect);
submitButton.Frame = new CGRect (10, 170, w - 20, 44);
submitButton.SetTitle ("Submit", UIControlState.Normal);
submitButton.TouchUpInside += (sender, e) => {
Console.WriteLine ("Submit button pressed");
};
View.AddSubview(submitButton);
これで、ログイン画面が次のように表示されます。
以前のバージョンの iOS とは異なり、既定のボタンの背景は透明です。 これはボタンの BackgroundColor
プロパティを変更することで変更できます。
submitButton.BackgroundColor = UIColor.White;
これにより、一般的な丸い枠付きボタンではなく、正方形のボタンが生成されます。 丸い枠を使用するには、次のスニペットを使用します。
submitButton.Layer.CornerRadius = 5f;
これらの変更により、ビューは次のようになります。
ビュー階層への複数のビューの追加
iOS には、AddSubviews
を使用してビュー階層に複数のビューを追加する機能が用意されています。
View.AddSubviews(new UIView[] { usernameField, passwordField, submitButton });
ボタン機能の追加
ボタンがクリックされると、ユーザーは何かが起こることを期待します。 たとえば、アラートが表示されたり、別の画面へとナビゲーションが実行されたりします。
ナビゲーション スタックに 2 つ目のビュー コントローラーをプッシュするコードを追加してみましょう。
最初に、2 つ目のビュー コントローラーを作成します。
var loginVC = new UIViewController () { Title = "Login Success!"};
loginVC.View.BackgroundColor = UIColor.Purple;
次に、TouchUpInside
イベントに機能を追加します。
submitButton.TouchUpInside += (sender, e) => {
this.NavigationController.PushViewController (loginVC, true);
};
ナビゲーションを次に示します。
既定では、ナビゲーション コントローラーを使用すると、iOS によってアプリケーションにナビゲーション バーと戻るボタンが表示され、スタック内を戻ることができることがわかります。
ビュー階層の反復処理
サブビュー階層を反復処理し、特定のビューを選択することができます。 たとえば、各 UIButton
を検索し、そのボタンに別の BackgroundColor
を与えるために、次のスニペットを使用できます。
foreach(var subview in View.Subviews)
{
if (subview is UIButton)
{
var btn = subview as UIButton;
btn.BackgroundColor = UIColor.Green;
}
}
ただし、これは、反復処理対象のビューが UIView
である場合は機能しません。親ビューに追加されたオブジェクト自体が UIView
を継承することから、すべてのビューが UIView
として返されるためです。
回転の処理
次のスクリーンショットに示すように、ユーザーがデバイスを横向きに回転させる場合、コントロールのサイズは適切に変更されません。
これを修正する方法の 1 つは、各ビューで AutoresizingMask
プロパティを設定する方法です。 この場合、コントロールを水平方向に拡大したいため、AutoresizingMask
をそれぞれ設定します。 次の例は usernameField
用ですが、ビュー階層内の各ガジェットにも同じ値を適用する必要があります。
usernameField.AutoresizingMask = UIViewAutoresizing.FlexibleWidth;
次に示すように、デバイスまたはシミュレーターを回転させると、すべてが拡張され、追加の領域が埋まるようにします。
カスタム ビューの作成
UIKit の一部であるコントロールを使用するだけでなく、カスタム ビューを使用することもできます。 カスタム ビューは、UIView
から継承し、Draw
をオーバーライドすることによって作成できます。 カスタム ビューを作成し、それをビュー階層に追加してデモを行いましょう。
UIView からの継承
最初に行う必要があるのは、カスタム ビューのクラスを作成することです。 これを行うには、Visual Studio のクラス テンプレートを使用して、CircleView
という名前の空のクラスを追加します。 基底クラスは UIView
に設定する必要があります。これは、UIKit
名前空間に存在しています。 System.Drawing
名前空間も必要になります。 この例では、他のさまざまな System.*
名前空間は使用されないため、自由に削除してください。
クラスは次のようになります。
using System;
namespace CodeOnlyDemo
{
class CircleView : UIView
{
}
}
UIView での描画
すべての UIView
には、描画する必要があるときにシステムによって呼び出される Draw
メソッドがあります。 Draw
は直接呼び出すべきではありません。 これは、実行ループの処理中にシステムによって呼び出されます。 実行ループを介してビューがビュー階層に初めて追加されると、その Draw
メソッドが呼び出されます。 後続の Draw
に対する呼び出しは、ビューで SetNeedsDisplay
または SetNeedsDisplayInRect
を呼び出すことでビューが描画が必要としてマークされたときに発生します。
次に示すように、オーバーライドされた Draw
メソッド内にこのようなコードを追加することで、ビューに描画コードを追加できます。
public override void Draw(CGRect rect)
{
base.Draw(rect);
//get graphics context
using (var g = UIGraphics.GetCurrentContext())
{
// set up drawing attributes
g.SetLineWidth(10.0f);
UIColor.Green.SetFill();
UIColor.Blue.SetStroke();
// create geometry
var path = new CGPath();
path.AddArc(Bounds.GetMidX(), Bounds.GetMidY(), 50f, 0, 2.0f * (float)Math.PI, true);
// add geometry to graphics context and draw
g.AddPath(path);
g.DrawPath(CGPathDrawingMode.FillStroke);
}
}
CircleView
は UIView
であるため、UIView
プロパティも設定できます。 たとえば、コンストラクターで BackgroundColor
を設定できます。
public CircleView()
{
BackgroundColor = UIColor.White;
}
先ほど作成した CircleView
を使用するには、前の UILabels
と UIButton
と同様に、既存のコントローラーのビュー階層にサブビューとして追加するか、新しいコントローラーのビューとして読み込むことができます。 後者を実行してみましょう。
ビューの読み込み
UIViewController
には、ビューを作成するためにコントローラーによって呼び出される LoadView
という名前のメソッドがあります。 これは、ビューを作成し、コントローラーの View
プロパティに割り当てるのに適した場所です。
まず、コントローラーが必要なので、CircleController
という名前の新しい空のクラスを作成します。
CircleController
で次のコードを追加して、View
を CircleView
に設定します (オーバーライドでは base
実装を呼び出さないでください)。
using UIKit;
namespace CodeOnlyDemo
{
class CircleController : UIViewController
{
CircleView view;
public override void LoadView()
{
view = new CircleView();
View = view;
}
}
}
最後に、実行時にコントローラーを提示する必要があります。 これを行うには、前に追加した送信ボタンにイベント ハンドラーを次のように追加します。
submitButton.TouchUpInside += delegate
{
Console.WriteLine("Submit button clicked");
//circleController is declared as class variable
circleController = new CircleController();
PresentViewController(circleController, true, null);
};
アプリケーションを実行して送信ボタンをタップすると、新しいビューに円が表示されます。
起動画面の作成
起動画面 は、アプリの起動時に、応答していることをユーザーに示す方法として表示されます。 起動画面はアプリの読み込み時に表示されるため、アプリケーションがまだメモリに読み込まれているため、コード内に作成することはできません。
Visual Studio で iOS プロジェクトを作成すると、起動画面は .xib ファイルの形式で提供されます。これは、プロジェクト内の Resources フォルダーにあります。
これを編集するには、ダブルクリックして Xcode Interface Builder で開きます。
Apple では、iOS 8 以降をターゲットとするアプリケーションでは .xib またはストーリーボード ファイルを使用することを推奨しています。Xcode Interface Builder でいずれかのファイルを起動すると、サイズ クラスと自動レイアウトを使用して、すべてのデバイス サイズに対して適切に表示されるようにレイアウトを調整できます。 静的起動イメージは、.xib または ストーリーボードに追加して使用することで、以前のバージョンを対象とするアプリケーションのサポートを可能にすることができます。
起動画面の作成の詳細については、以下のドキュメントを参照してください。
重要
iOS 9 の時点で、Apple では、起動画面を作成する主な方法としてストーリーボードを使用することを推奨しています。
iOS 8 より前のアプリケーションの起動イメージの作成
アプリケーションが iOS 8 より前のバージョンを対象とする場合は、.xib またはストーリーボードの起動画面に加えて静的イメージを使用できます。
この静的イメージは、Info.plist ファイルで設定することも、アプリケーションのアセット カタログ (iOS 7 の場合) として設定することもできます。 アプリケーションを実行できるデバイス サイズ (320x480、640x960、640x1136) ごとに個別のイメージを指定する必要があります。 起動画面のサイズの詳細については、「起動画面イメージ」ガイドを参照してください。
重要
アプリに起動画面がない場合は、画面に完全に収まっていないことがあります。 この場合は、Info.plist に Default-568@2x.png
という名前の 640x1136 イメージが最小限含まれている必要があります。
まとめ
この記事では、Visual Studio で iOS アプリケーションをプログラムで開発する方法について説明しました。 空のプロジェクト テンプレートからプロジェクトをビルドする方法について説明し、ルート ビュー コントローラーを作成してウィンドウに追加する方法について説明しました。 次に、UIKit のコントロールを使用して、コントローラー内にビュー階層を作成し、アプリケーション画面を開発する方法について説明しました。 次に、ビューをさまざまな向きで適切にレイアウトする方法を調べ、UIView
をサブクラス化してカスタム ビューを作成する方法と、コントローラー内でビューを読み込む方法を確認しました。 最後に、アプリケーションに起動画面を追加する方法について説明しました。