Xamarin.iOS の統合ストーリーボード

iOS 8 には、ユーザー インターフェイス (統合されたストーリーボード) を作成するための新しい、より簡単に使用できるメカニズムが含まれています。 さまざまなハードウェア画面サイズをすべてカバーする 1 つのストーリーボードを使用すると、高速で応答性の高いビューを "デザイン 1 回、 use-many" スタイルで作成できます。

開発者は iPhone および iPad デバイス用に個別の特定のストーリーボードを作成する必要がなくなったため、共通のインターフェイスを使用してアプリケーションを設計し、そのインターフェイスをさまざまなサイズのクラスに合わせてカスタマイズする柔軟性があります。 このようにして、アプリケーションを各フォーム ファクターの長所に合わせて調整し、各ユーザー インターフェイスを調整して最適なエクスペリエンスを提供できます。

サイズ クラス

iOS 8 より前の開発者は、 と UIInterfaceIdiom を使用UIInterfaceOrientationして縦モードと横モードを区別し、iPhone と iPad デバイスを区別しました。 iOS8 では、方向とデバイスは サイズ クラスを使用して決定されます。

デバイスは、垂直軸と水平軸の両方でサイズ クラスによって定義され、iOS 8 には 2 種類のサイズ クラスがあります。

  • 通常 – これは、大きな画面サイズ (iPad など) または大きなサイズの印象を与えるガジェット (たとえば、 UIScrollView
  • コンパクト – これは、小さなデバイス (iPhone など) 用です。 このサイズでは、デバイスの向きが考慮されます。

2 つの概念を組み合わせて使用すると、次の図に示すように、両方の異なる向きで使用できるさまざまなサイズを定義する 2 x 2 グリッドが生成されます。

標準方向とコンパクト方向で使用できるさまざまなサイズを定義する 2 x 2 グリッド

開発者は、(上の図に示すように) 異なるレイアウトになる 4 つの可能性のいずれかを使用するビュー コントローラーを作成できます。

iPad サイズ クラス

サイズにより、iPad には両方の向きの 通常 のクラス サイズがあります。

iPad サイズ クラス

iPhone サイズ クラス

iPhone には、デバイスの向きに基づいてサイズ クラスが異なります。

iPhone サイズ クラス

  • デバイスが縦モードの場合、画面は水平方向と垂直方向に定期的コンパクトなクラスを持っています
  • デバイスが横モードの場合、画面クラスは縦モードから反転されます。

iPhone 6 Plus Size クラス

縦向きの場合、サイズは以前の iPhone と同じですが、横向きでは異なります。

iPhone 6 Plus Size クラス

iPhone 6 Plusには十分な大きさの画面があるため、横モードで標準の幅サイズクラスを使用できます。

新しい画面スケールのサポート

iPhone 6 Plusは、画面スケールファクターが3.0(元のiPhoneの画面解像度の3倍)の新しいRetina HDディスプレイを使用しています。 これらのデバイスで可能な限り最高のエクスペリエンスを提供するには、この画面スケール用に設計された新しいアートワークを含めます。 Xcode 6 以降では、アセット カタログには 1x、2x、3x サイズのイメージを含めることができます。新しいイメージアセットを追加するだけで、iPhone 6 Plusで実行するときにiOSは正しいアセットを選択します。

iOS のイメージ読み込み動作では、イメージ ファイルの @3x サフィックスも認識されます。 たとえば、開発者がアプリケーションのバンドルにイメージ資産 (異なる解像度で) を含め、ファイル名 MonkeyIcon.pngMonkeyIcon@2x.png、、および MonkeyIcon@3x.pngを含む場合です。 iPhone 6 Plus では、開発者が次のコードを MonkeyIcon@3x.png 使用してイメージを読み込む場合、イメージが自動的に使用されます。

UIImage icon = UIImage.FromFile("MonkeyImage.png");

動的起動画面

起動画面ファイルは、iOS アプリケーションの起動時にスプラッシュ スクリーンとして表示され、アプリが実際に起動中であることをユーザーにフィードバックします。 iOS 8 より前では、開発者は、アプリケーションが実行されるデバイスの種類、向き、画面解像度ごとに複数 Default.png の画像資産を含める必要がありました。

iOS 8 を初めて使用する開発者は、自動レイアウトとサイズ クラスを使用して、すべてのデバイス、解像度、向きに対応する動的起動画面を作成する単一のアトミック .xib ファイルを Xcode に作成できます。 これにより、開発者が必要なすべてのイメージ資産を作成および保守するために必要な作業量が削減されるだけでなく、アプリケーションのインストール済みバンドルのサイズが小さくなります。

Traits

特徴は、環境の変化に応じてレイアウトがどのように変化するかを決定するために使用できるプロパティです。 これらは、一連のプロパティ ( HorizontalSizeClass および VerticalSizeClassUIUserInterfaceSizeClass基づく) と、インターフェイスのイディオム ( UIUserInterfaceIdiom) と表示スケールで構成されます。

上記のすべての状態は、Apple が Trait Collection ( UITraitCollection) と呼ぶコンテナーにラップされます。このコンテナーには、プロパティだけでなく、その値も含まれます。

特性環境

Trait Environments は iOS 8 の新しいインターフェイスであり、次のオブジェクトの Trait コレクションを返すことができます。

  • 画面 ( UIScreens )。
  • Windows ( UIWindows )。
  • ビュー コントローラー ( UIViewController )。
  • Views ( UIView )。
  • プレゼンテーション コントローラー ( UIPresentationController )。

開発者は、Trait Environment によって返される Trait コレクションを使用して、ユーザー インターフェイスのレイアウト方法を決定します。

すべての特徴環境は、次の図に示すように階層を作成します。

Trait Environments 階層図

上記の各特徴環境に含まれる Trait コレクションは、既定で親環境から子環境にフローされます。

Trait Environment には TraitCollectionDidChange 、現在の Trait コレクションの取得に加えて、View または View Controller サブクラスでオーバーライドできるメソッドがあります。 開発者は、このメソッドを使用して、特性が変更されたときに特性に依存する UI 要素を変更できます。

一般的な特徴コレクション

このセクションでは、iOS 8 を使用するときにユーザーが経験する特徴コレクションの一般的な種類について説明します。

開発者が iPhone に表示する一般的な特徴コレクションを次に示します。

プロパティ
HorizontalSizeClass コンパクト
VerticalSizeClass 通常
UserInterfaceIdom Phone
DisplayScale 2.0

上記のセットは、すべての特性プロパティの値を持つ完全修飾特徴コレクションを表します。

また、値の一部が欠落している Trait コレクションを作成することもできます (Apple は Unspecified と呼びます)。

プロパティ
HorizontalSizeClass コンパクト
VerticalSizeClass 指定されていません。
UserInterfaceIdom 指定されていません。
DisplayScale 指定されていません。

ただし、一般に、開発者が Trait Environment に Trait Collection を要求すると、上の例に示すように完全修飾コレクションが返されます。

特徴環境 (ビューやビュー コントローラーなど) が現在のビュー階層の内部にない場合、開発者は 1 つ以上の特性プロパティの未指定の値を取得する可能性があります。

開発者は、Apple によって提供される作成方法の 1 つ ( など UITraitCollection.FromHorizontalSizeClass) を使用して新しいコレクションを作成する場合も、部分的に修飾された Trait コレクションを取得します。

複数の特徴コレクションに対して実行できる 1 つの操作は、それらを相互に比較することです。これには、1 つの特徴コレクションに別の特徴コレクションが含まれているかどうかを確認する必要があります。 Containment の意味は、2 番目のコレクションで指定された特性に対して、値が最初のコレクションの値と正確に一致する必要があるということです。

2 つの特徴をテストするには、テストする Contains 特徴の値を UITraitCollection 渡す の メソッドを使用します。

開発者は、コード内で比較を手動で実行して、ビューまたはビュー コントローラーのレイアウト方法を決定できます。 ただし、 UIKit このメソッドを内部的に使用して、たとえば、外観プロキシのように、その機能の一部を提供します。

外観プロキシ

外観プロキシは、開発者がビューのプロパティをカスタマイズできるように、以前のバージョンの iOS で導入されました。 iOS 8 では、Trait コレクションをサポートするように拡張されています。

外観プロキシには、 AppearanceForTraitCollection渡された特定の Trait コレクションの新しい外観プロキシを返す新しいメソッド が含まれるようになりました。 開発者がその外観プロキシに対して実行するカスタマイズは、指定された Trait コレクションに準拠するビューでのみ有効になります。

一般に、開発者は、部分的に指定された Trait Collection を メソッドに AppearanceForTraitCollection 渡します。たとえば、 Horizontal Size Class of Compact を指定したメソッドなどです。これにより、水平方向にコンパクトなアプリケーション内の任意のビューをカスタマイズできます。

UIImage

Apple が Trait Collection を に追加したもう 1 つのクラスは です UIImage。 これまで、開発者は、アプリケーションに含めるビットマップグラフィックアセットの@1Xと@2xバージョン (アイコンなど) を指定する必要がありました。

iOS 8 が拡張され、開発者は特徴コレクションに基づいてイメージ カタログに複数のバージョンのイメージを含めることができます。 たとえば、開発者は、Compact Trait クラスを操作するための小さなイメージと、他のコレクション用のフルサイズのイメージを含めることができます。

クラス内 UIImageView でイメージの 1 つが使用されると、Image View によって、その Trait Collection のイメージの正しいバージョンが自動的に表示されます。 特性環境が変更された場合 (ユーザーがデバイスを縦から横に切り替える場合など)、イメージ ビューは新しい特性コレクションに合わせて新しい画像サイズを自動的に選択し、表示されているイメージの現在のバージョンと一致するようにサイズを変更します。

UIImageAsset

Apple は、開発者が画像の選択をより詳細に制御できるように、 という名前 UIImageAsset の新しいクラスを iOS 8 に追加しました。

Image Asset は、イメージのすべての異なるバージョンをラップし、渡された Trait コレクションに一致する特定のイメージを開発者が要求できるようにします。 イメージは、イメージアセットに追加したり、その場で削除したりできます。

Image Assets の詳細については、Apple の UIImageAsset ドキュメントを参照してください。

特徴コレクションの組み合わせ

開発者が Trait Collections に対して実行できるもう 1 つの関数は、結合されたコレクションになる 2 つを追加することです。この場合、1 つのコレクションの指定されていない値は、2 つ目のコレクションの指定された値に置き換えられます。 これは、 クラスの メソッドをFromTraitsFromCollectionsUITraitCollection使用して行われます。

前述のように、いずれかの特性がいずれかの特性コレクションで指定されておらず、別の特性コレクションで指定されている場合、値は指定されたバージョンに設定されます。 ただし、指定された値の複数のバージョンが指定されている場合は、最後の Trait Collection の値が使用される値になります。

アダプティブ ビュー コントローラー

このセクションでは、iOS ビューおよびビュー コントローラーが特徴クラスとサイズ クラスの概念を採用して、開発者のアプリケーションで自動的により適応性を高める方法の詳細について説明します。

分割ビュー コントローラー

iOS 8 で最も変更されたビュー コントローラー クラスの 1 つが クラスです UISplitViewController 。 以前は、開発者は多くの場合、アプリケーションの iPad バージョンで分割ビュー コントローラーを使用し、その後、アプリの iPhone バージョンに対してまったく異なるバージョンのビュー階層を提供する必要があります。

iOS 8 では、 UISplitViewController クラスは両方のプラットフォーム (iPad と iPhone) で使用できます。これにより、開発者は iPhone と iPad の両方で機能するビュー コントローラー階層を 1 つ作成できます。

iPhone が横向きにある場合、分割ビュー コントローラーは、iPad に表示される場合と同様に、ビューを並べて表示します。

特性のオーバーライド

Trait Environments は、横向きの iPad の分割ビュー コントローラーを示す次の図のように、親コンテナーから子コンテナーにカスケードされます。

横向きの iPad の分割ビュー コントローラー

iPad には水平方向と垂直方向の両方に標準サイズ クラスがあるため、分割ビューにはマスター ビューと詳細ビューの両方が表示されます。

サイズ クラスが両方向でコンパクトな iPhone では、分割ビュー コントローラーは詳細ビューのみを表示します。次に示します。

分割ビュー コントローラーには詳細ビューのみが表示されます

開発者が iPhone のマスター ビューと詳細ビューの両方を横向きで表示するアプリケーションでは、開発者は分割ビュー コントローラーの親コンテナーを挿入し、Trait コレクションをオーバーライドする必要があります。 次の図に示すように、

開発者は、分割ビュー コントローラーの親コンテナーを挿入し、Trait コレクションをオーバーライドする必要があります

UIViewは分割ビュー コントローラーの親として設定され、SetOverrideTraitCollection新しい Trait Collection を渡して分割ビュー コントローラーを対象とするビューで メソッドが呼び出されます。 新しい Trait Collection は、 HorizontalSizeClassを オーバーライドし、 を に Regular設定して、分割ビュー コントローラーが横向きの iPhone のマスター ビューと詳細ビューの両方を表示するようにします。

VerticalSizeClassが に設定されていることにunspecified注意してください。これにより、新しい Trait コレクションを親の Trait Collection に追加でき、その結果Compact VerticalSizeClass、子の分割ビュー コントローラーの が作成されます。

特性の変更

このセクションでは、特徴環境が変化したときに特徴コレクションがどのように遷移するかを詳しく見ていきます。 たとえば、デバイスが縦から横に回転する場合などです。

縦から横の特徴の変更の概要

まず、iOS 8 では、移行を行う準備のためにいくつかのセットアップが行われます。 次に、システムは遷移状態をアニメーション化します。 最後に、iOS 8 は、移行中に必要な一時的な状態をすべてクリーンアップします。

iOS 8 には、次の表に示すように、開発者が特性の変更に参加するために使用できるコールバックがいくつか用意されています。

段階 コールバック Description
セットアップ
  • WillTransitionToTraitCollection
  • TraitCollectionDidChange
  • このメソッドは、Trait Collection が新しい値に設定される前に、Trait Change の先頭で呼び出されます。
  • メソッドは、Trait Collection の値が変更されたが、アニメーションが実行される前に呼び出されます。
アニメーション WillTransitionToTraitCollection このメソッドに渡される遷移コーディネーターには AnimateAlongside 、開発者が既定のアニメーションと共に実行されるアニメーションを追加できるプロパティがあります。
クリーンアップ WillTransitionToTraitCollection 移行後に開発者が独自のクリーンアップ コードを含めるメソッドを提供します。

このメソッドは WillTransitionToTraitCollection 、ビュー コントローラーと特性コレクションの変更をアニメーション化するために最適です。 メソッドは WillTransitionToTraitCollection ビュー コントローラー ( UIViewController) でのみ使用でき、 などの UIViews他の特性環境では使用できません。

TraitCollectionDidChangeは、 クラスをUIView操作するのに最適です。開発者は、特性が変化するにつれて UI を更新したいと考えています。

分割ビュー コントローラーの折りたたみ

次に、分割ビュー コントローラーが 2 つの列から 1 つの列ビューに折りたたまれた場合の動作を詳しく見てみましょう。 この変更の一環として、次の 2 つのプロセスを実行する必要があります。

  • 既定では、分割ビュー コントローラーでは、折りたたみが発生した後、ビューとしてプライマリ ビュー コントローラーが使用されます。 開発者は、 の UISplitViewControllerDelegate メソッドをGetPrimaryViewControllerForCollapsingSplitViewControllerオーバーライドし、折りたたまれた状態で表示するビュー コントローラーを指定することで、この動作をオーバーライドできます。
  • セカンダリ ビュー コントローラーは、プライマリ ビュー コントローラーにマージされる必要があります。 一般に、開発者はこの手順に対して何も行う必要はありません。分割ビュー コントローラーには、ハードウェア デバイスに基づくこのフェーズの自動処理が含まれています。 ただし、開発者がこの変更とやり取りする特別なケースが存在する場合があります。 の UISplitViewControllerDelegate メソッドをCollapseSecondViewController呼び出すと、詳細ビューではなく、折りたたみが発生したときにマスター ビュー コントローラーを表示できます。

分割ビュー コントローラーの展開

次に、分割ビュー コントローラーが折りたたまれた状態から展開された場合の動作を詳しく見てみましょう。 もう一度、次の 2 つのステージを実行する必要があります。

  • まず、新しいプライマリ ビュー コントローラーを定義します。 既定では、分割ビュー コントローラーでは、折りたたまれたビューからプライマリ ビュー コントローラーが自動的に使用されます。 ここでも、開発者は の メソッドを使用してこの動作を GetPrimaryViewControllerForExpandingSplitViewControllerUISplitViewControllerDelegate オーバーライドできます。
  • プライマリ ビュー コントローラーが選択されたら、セカンダリ ビュー コントローラーを再作成する必要があります。 ここでも、分割ビュー コントローラーには、ハードウェア デバイスに基づくこのフェーズの自動処理が含まれています。 開発者は、 の メソッドを SeparateSecondaryViewController 呼び出すことによって、この動作を UISplitViewControllerDelegate オーバーライドできます。

分割ビュー コントローラーでは、プライマリ ビュー コントローラーは の メソッドと SeparateSecondaryViewController メソッドを実装CollapseSecondViewControllerすることで、ビューの展開と折りたたみの両方で一部をUISplitViewControllerDelegate果たします。 UINavigationController は、セカンダリ ビュー コントローラーを自動的にプッシュおよびポップするために、これらのメソッドを実装します。

ビュー コントローラーの表示

Apple が iOS 8 に加えたもう 1 つの変更は、開発者がビュー コントローラーを表示する方法です。 以前は、アプリケーションにリーフ ビュー コントローラー (テーブル ビュー コントローラーなど) があり、開発者が別のものを表示した場合 (たとえば、ユーザーがセルをタップした場合など)、アプリケーションはコントローラー階層を経由してナビゲーション ビュー コントローラーに戻り、それに対して メソッドを呼び出 PushViewController して新しいビューを表示していました。

これにより、ナビゲーション コントローラーと、それが実行されていた環境との間に非常に緊密な結合が示されました。 iOS 8 では、Apple は 2 つの新しい方法を提供することでこれを切り離しました。

  • ShowViewController – 環境に基づいて新しいビュー コントローラーを表示するように適応します。 たとえば、 では UINavigationController 単に新しいビューをスタックにプッシュします。 分割ビュー コントローラーでは、新しいビュー コントローラーが新しいプライマリ ビュー コントローラーとして左側に表示されます。 コンテナー ビュー コントローラーが存在しない場合、新しいビューはモーダル ビュー コントローラーとして表示されます。
  • ShowDetailViewController – と同様の方法 ShowViewControllerで動作しますが、分割ビュー コントローラーで実装され、詳細ビューを渡される新しいビュー コントローラーに置き換えます。 分割ビュー コントローラーが折りたたまれている場合 (iPhone アプリケーションで見られるように)、呼び出しは メソッドに ShowViewController リダイレクトされ、新しいビューはプライマリ ビュー コントローラーとして表示されます。 ここでも、コンテナー ビュー コントローラーが存在しない場合、新しいビューはモーダル ビュー コントローラーとして表示されます。

これらのメソッドは、リーフ ビュー コントローラーから開始し、新しいビューの表示を処理する適切なコンテナー ビュー コントローラーが見つかるまでビュー階層をウォークアップすることで機能します。

開発者は、 および ShowDetailViewController を独自のカスタム ビュー コントローラーに実装ShowViewControllerして、提供するのとUISplitViewController同じ自動化された機能をUINavigationController取得できます。

しくみ

このセクションでは、これらのメソッドが実際に iOS 8 でどのように実装されているかを見ていきます。 まず、新しい GetTargetForAction メソッドを見てみましょう。

新しい GetTargetForAction メソッド

このメソッドは、適切なコンテナー ビュー コントローラーが見つかるまで階層チェーンを歩きます。 次に例を示します。

  1. メソッドが ShowViewController 呼び出された場合、このメソッドを実装するチェーン内の最初のビュー コントローラーはナビゲーション コントローラーであるため、新しいビューの親として使用されます。
  2. 代わりにメソッドが ShowDetailViewController 呼び出された場合、分割ビュー コントローラーは、それを実装する最初のビュー コントローラーであるため、親として使用されます。

メソッドは GetTargetForAction 、特定のアクションを実装するビュー コントローラーを検索し、そのアクションを受け取るかどうかをビュー コントローラーに要求することで機能します。 このメソッドはパブリックであるため、開発者は、組み込みの メソッドや メソッドとShowDetailViewController同様に機能する独自のShowViewControllerカスタム メソッドを作成できます。

アダプティブ プレゼンテーション

iOS 8 では、Apple は Popover Presentations ( UIPopoverPresentationController) もアダプティブにしました。 そのため、ポップオーバー プレゼンテーション ビュー コントローラーは通常のポップオーバー ビューを標準サイズ クラスで自動的に表示しますが、水平方向にコンパクトなサイズ クラス (iPhone など) で全画面表示します。

統合ストーリーボード システム内の変更に対応するために、表示されるビュー コントローラーを管理するための新しいコントローラー オブジェクトが作成されました。 UIPresentationController このコントローラーは、ビュー コントローラーが表示されてから閉じるまで作成されます。 管理クラスであるため、ビュー コントローラーに影響を与えるデバイスの変更 (向きなど) に応答し、プレゼンテーション コントローラーコントロールのビュー コントローラーにフィードバックされるため、ビュー コントローラー上のスーパー クラスと見なすことができます。

開発者が メソッドを使用してビュー コントローラーを PresentViewController 提示すると、プレゼンテーション プロセスの管理が に UIKit渡されます。 UIKit は、(特に) 作成されるスタイルの正しいコントローラーを処理します。唯一の例外は、ビュー コントローラーのスタイルが に UIModalPresentationCustom設定されている場合です。 ここでは、アプリケーションは、コントローラーを使用するのではなく、独自の PresentationController を UIKit 提供できます。

ユーザー設定のプレゼンテーション スタイル

カスタム プレゼンテーション スタイルでは、開発者はカスタム プレゼンテーション コントローラーを使用できます。 このカスタム コントローラーを使用して、そのユーザー設定のビューの外観と動作を変更できます。

サイズ クラスの操作

この記事に含まれているアダプティブフォト Xamarin プロジェクトでは、iOS 8 統合インターフェイス アプリケーションでサイズ クラスとアダプティブ ビュー コントローラーを使用する実際の例を示します。

アプリケーションでは、Xcode の Interface Builder を使用して統合ストーリーボードを作成するのではなく、コードから UI を完全に作成しますが、同じ手法が適用されます。

次に、アダプティブフォトプロジェクトがiOS 8のサイズクラス機能のいくつかを実装してアダプティブアプリケーションを作成する方法を詳しく見てみましょう。

特性環境の変化への適応

iPhone で Adaptive Photos アプリケーションを実行すると、ユーザーがデバイスを縦から横に回転すると、分割ビュー コントローラーにマスター ビューと詳細ビューの両方が表示されます。

分割ビュー コントローラーには、次に示すようにマスター ビューと詳細ビューの両方が表示されます

これを行うには、ビュー コントローラーの メソッドを UpdateConstraintsForTraitCollection オーバーライドし、 の値 VerticalSizeClassに基づいて制約を調整します。 次に例を示します。

public void UpdateConstraintsForTraitCollection (UITraitCollection collection)
{
    var views = NSDictionary.FromObjectsAndKeys (
        new object[] { TopLayoutGuide, ImageView, NameLabel, ConversationsLabel, PhotosLabel },
        new object[] { "topLayoutGuide", "imageView", "nameLabel", "conversationsLabel", "photosLabel" }
    );

    var newConstraints = new List<NSLayoutConstraint> ();
    if (collection.VerticalSizeClass == UIUserInterfaceSizeClass.Compact) {
        newConstraints.AddRange (NSLayoutConstraint.FromVisualFormat ("|[imageView]-[nameLabel]-|",
            NSLayoutFormatOptions.DirectionLeadingToTrailing, null, views));

        newConstraints.AddRange (NSLayoutConstraint.FromVisualFormat ("[imageView]-[conversationsLabel]-|",
            NSLayoutFormatOptions.DirectionLeadingToTrailing, null, views));

        newConstraints.AddRange (NSLayoutConstraint.FromVisualFormat ("[imageView]-[photosLabel]-|",
            NSLayoutFormatOptions.DirectionLeadingToTrailing, null, views));

        newConstraints.AddRange (NSLayoutConstraint.FromVisualFormat ("V:|[topLayoutGuide]-[nameLabel]-[conversationsLabel]-[photosLabel]",
            NSLayoutFormatOptions.DirectionLeadingToTrailing, null, views));

        newConstraints.AddRange (NSLayoutConstraint.FromVisualFormat ("V:|[topLayoutGuide][imageView]|",
            NSLayoutFormatOptions.DirectionLeadingToTrailing, null, views));

        newConstraints.Add (NSLayoutConstraint.Create (ImageView, NSLayoutAttribute.Width, NSLayoutRelation.Equal,
            View, NSLayoutAttribute.Width, 0.5f, 0.0f));
    } else {
        newConstraints.AddRange (NSLayoutConstraint.FromVisualFormat ("|[imageView]|",
            NSLayoutFormatOptions.DirectionLeadingToTrailing, null, views));

        newConstraints.AddRange (NSLayoutConstraint.FromVisualFormat ("|-[nameLabel]-|",
            NSLayoutFormatOptions.DirectionLeadingToTrailing, null, views));

        newConstraints.AddRange (NSLayoutConstraint.FromVisualFormat ("|-[conversationsLabel]-|",
            NSLayoutFormatOptions.DirectionLeadingToTrailing, null, views));

        newConstraints.AddRange (NSLayoutConstraint.FromVisualFormat ("|-[photosLabel]-|",
            NSLayoutFormatOptions.DirectionLeadingToTrailing, null, views));

        newConstraints.AddRange (NSLayoutConstraint.FromVisualFormat ("V:[topLayoutGuide]-[nameLabel]-[conversationsLabel]-[photosLabel]-20-[imageView]|",
            NSLayoutFormatOptions.DirectionLeadingToTrailing, null, views));
    }

    if (constraints != null)
        View.RemoveConstraints (constraints.ToArray ());

    constraints = newConstraints;
    View.AddConstraints (constraints.ToArray ());
}

画面切り替えアニメーションの追加

アダプティブ写真アプリケーションの分割ビュー コントローラーが折りたたまれた状態から展開された状態になると、ビュー コントローラーの メソッドをオーバーライド WillTransitionToTraitCollection することで、既定のアニメーションにアニメーションが追加されます。 次に例を示します。

public override void WillTransitionToTraitCollection (UITraitCollection traitCollection, IUIViewControllerTransitionCoordinator coordinator)
{
    base.WillTransitionToTraitCollection (traitCollection, coordinator);
    coordinator.AnimateAlongsideTransition ((UIViewControllerTransitionCoordinatorContext) => {
        UpdateConstraintsForTraitCollection (traitCollection);
        View.SetNeedsLayout ();
    }, (UIViewControllerTransitionCoordinatorContext) => {
    });
}

特性環境のオーバーライド

上に示すように、アダプティブフォトアプリケーションは、iPhoneデバイスが横向きビューにあるときに詳細とマスタービューの両方を表示するように分割ビューコントローラを強制します。

これを行うには、ビュー コントローラーで次のコードを使用します。

private UITraitCollection forcedTraitCollection = new UITraitCollection ();
...

public UITraitCollection ForcedTraitCollection {
    get {
        return forcedTraitCollection;
    }

    set {
        if (value != forcedTraitCollection) {
            forcedTraitCollection = value;
            UpdateForcedTraitCollection ();
        }
    }
}
...

public override void ViewWillTransitionToSize (SizeF toSize, IUIViewControllerTransitionCoordinator coordinator)
{
    ForcedTraitCollection = toSize.Width > 320.0f ?
         UITraitCollection.FromHorizontalSizeClass (UIUserInterfaceSizeClass.Regular) :
         new UITraitCollection ();

    base.ViewWillTransitionToSize (toSize, coordinator);
}

public void UpdateForcedTraitCollection ()
{
    SetOverrideTraitCollection (forcedTraitCollection, viewController);
}

分割ビュー コントローラーの展開と折りたたみ

次に、分割ビュー コントローラーの展開と折りたたみの動作が Xamarin でどのように実装されたかを調べてみましょう。 では、 AppDelegate分割ビュー コントローラーが作成されると、次の変更を処理するためにそのデリゲートが割り当てられます。

public class SplitViewControllerDelegate : UISplitViewControllerDelegate
{
    public override bool CollapseSecondViewController (UISplitViewController splitViewController,
        UIViewController secondaryViewController, UIViewController primaryViewController)
    {
        AAPLPhoto photo = ((CustomViewController)secondaryViewController).Aapl_containedPhoto (null);
        if (photo == null) {
            return true;
        }

        if (primaryViewController.GetType () == typeof(CustomNavigationController)) {
            var viewControllers = new List<UIViewController> ();
            foreach (var controller in ((UINavigationController)primaryViewController).ViewControllers) {
                var type = controller.GetType ();
                MethodInfo method = type.GetMethod ("Aapl_containsPhoto");

                if ((bool)method.Invoke (controller, new object[] { null })) {
                    viewControllers.Add (controller);
                }
            }

            ((UINavigationController)primaryViewController).ViewControllers = viewControllers.ToArray<UIViewController> ();
        }

        return false;
    }

    public override UIViewController SeparateSecondaryViewController (UISplitViewController splitViewController,
        UIViewController primaryViewController)
    {
        if (primaryViewController.GetType () == typeof(CustomNavigationController)) {
            foreach (var controller in ((CustomNavigationController)primaryViewController).ViewControllers) {
                var type = controller.GetType ();
                MethodInfo method = type.GetMethod ("Aapl_containedPhoto");

                if (method.Invoke (controller, new object[] { null }) != null) {
                    return null;
                }
            }
        }

        return new AAPLEmptyViewController ();
    }
}

メソッドは SeparateSecondaryViewController 、写真が表示されているかどうかをテストし、その状態に基づいてアクションを実行します。 写真が表示されていない場合は、マスター ビュー コントローラーが表示されるようにセカンダリ ビュー コントローラーが折りたたまれます。

分割 CollapseSecondViewController ビュー コントローラーを展開してスタック上に写真が存在するかどうかを確認する場合は、そのビューに折りたたまれる場合は、 メソッドを使用します。

ビュー コントローラー間の移動

次に、アダプティブ写真アプリケーションがビュー コントローラー間でどのように移動するかを見てみましょう。 ユーザーが AAPLConversationViewController テーブル ShowDetailViewController からセルを選択すると、 クラスで、 メソッドが呼び出されて詳細ビューが表示されます。

public override void RowSelected (UITableView tableView, NSIndexPath indexPath)
{
    var photo = PhotoForIndexPath (indexPath);
    var controller = new AAPLPhotoViewController ();
    controller.Photo = photo;

    int photoNumber = indexPath.Row + 1;
    int photoCount = (int)Conversation.Photos.Count;
    controller.Title = string.Format ("{0} of {1}", photoNumber, photoCount);
    ShowDetailViewController (controller, this);
}

開示インジケーターの表示

アダプティブ写真アプリケーションでは、特性環境の変更に基づいて開示インジケーターが非表示になっているか、表示される場所がいくつかあります。 これは、次のコードで処理されます。

public bool Aapl_willShowingViewControllerPushWithSender ()
{
    var selector = new Selector ("Aapl_willShowingViewControllerPushWithSender");
    var target = this.GetTargetViewControllerForAction (selector, this);

    if (target != null) {
        var type = target.GetType ();
        MethodInfo method = type.GetMethod ("Aapl_willShowingDetailViewControllerPushWithSender");
        return (bool)method.Invoke (target, new object[] { });
    } else {
        return false;
    }
}

public bool Aapl_willShowingDetailViewControllerPushWithSender ()
{
    var selector = new Selector ("Aapl_willShowingDetailViewControllerPushWithSender");
    var target = this.GetTargetViewControllerForAction (selector, this);

    if (target != null) {
        var type = target.GetType ();
        MethodInfo method = type.GetMethod ("Aapl_willShowingDetailViewControllerPushWithSender");
        return (bool)method.Invoke (target, new object[] { });
    } else {
        return false;
    }
}

これらは、上記で詳しく説明したメソッドを GetTargetViewControllerForAction 使用して実装されます。

テーブル ビュー コントローラーは、データを表示するときに、上で実装したメソッドを使用して、プッシュが行われるかどうかを確認し、それに応じて開示インジケーターを表示または非表示にするかどうかを確認します。

public override void WillDisplay (UITableView tableView, UITableViewCell cell, NSIndexPath indexPath)
{
    bool pushes = ShouldShowConversationViewForIndexPath (indexPath) ?
         Aapl_willShowingViewControllerPushWithSender () :
         Aapl_willShowingDetailViewControllerPushWithSender ();

    cell.Accessory = pushes ? UITableViewCellAccessory.DisclosureIndicator : UITableViewCellAccessory.None;
    var conversation = ConversationForIndexPath (indexPath);
    cell.TextLabel.Text = conversation.Name;
}

新しい ShowDetailTargetDidChangeNotification

Apple では、分割ビュー コントローラー ShowDetailTargetDidChangeNotification内からサイズ クラスと特性環境を操作するための新しい通知の種類が追加されました。 この通知は、コントローラーの展開や折りたたみなど、分割ビュー コントローラーのターゲット詳細ビューが変更されるたびに送信されます。

Adaptive Photos アプリケーションでは、この通知を使用して、詳細ビュー コントローラーが変更されたときに開示インジケーターの状態を更新します。

public override void ViewDidLoad ()
{
    base.ViewDidLoad ();
    TableView.RegisterClassForCellReuse (typeof(UITableViewCell), AAPLListTableViewControllerCellIdentifier);
    NSNotificationCenter.DefaultCenter.AddObserver (this, new Selector ("showDetailTargetDidChange:"),
        UIViewController.ShowDetailTargetDidChangeNotification, null);
    ClearsSelectionOnViewWillAppear = false;
}

Adaptive Photos アプリケーションを詳しく見て、サイズ クラス、特性コレクション、アダプティブ ビュー コントローラーを使用して Xamarin.iOS で統合アプリケーションを簡単に作成できるすべての方法を確認します。

統合ストーリーボード

iOS 8 の新機能である統合ストーリーボードを使用すると、開発者は複数のサイズ クラスをターゲットにして、iPhone と iPad の両方のデバイスに表示できる統合されたストーリーボード ファイルを 1 つ作成できます。 統合ストーリーボードを使用することで、開発者はより少ない UI 固有のコードを記述し、作成と保守を行うインターフェイスデザインは 1 つだけです。

統合ストーリーボードの主な利点は次のとおりです。

  • iPhone と iPad に同じストーリーボード ファイルを使用します。
  • iOS 6 と iOS 7 に後方に展開します。
  • さまざまなデバイス、向き、OS バージョンのレイアウトをプレビューします。

サイズ クラスの有効化

既定では、新しい Xamarin.iOS プロジェクトではサイズ クラスが使用されます。 古いプロジェクトのストーリーボード内でサイズ クラスとアダプティブ セグエを使用するには、まず Xcode 6 統合ストーリーボード形式に変換し、ストーリーボードの Xcode ファイル インスペクター内で [サイズ クラスの使用] チェック ボックスをオンにする必要があります。

動的起動画面

起動画面ファイルは、iOS アプリケーションの起動時にスプラッシュ スクリーンとして表示され、アプリが実際に起動中であることをユーザーにフィードバックします。 iOS 8 より前では、開発者は、アプリケーションが実行されるデバイスの種類、向き、画面解像度ごとに複数 Default.png の画像資産を含める必要がありました。 たとえば、、、Default@2x.pngDefault-Landscape@2x~ipad.pngDefault-Portrait@2x~ipad.png、などです。

新しい iPhone 6 および iPhone 6 Plus デバイス (および今後の Apple Watch) と既存のすべての iPhone および iPad デバイスを考慮すると、これは、作成および維持する必要があるスタートアップ画面イメージ資産のさまざまなサイズ、向き、解像度の Default.png 大きな配列を表します。 さらに、これらのファイルは非常に大きく、成果物のアプリケーションバンドルを「肥大化」させ、iTunes App Storeからアプリケーションをダウンロードするために必要な時間を増やし(携帯電話ネットワーク経由で配信できないようにする可能性があります)、エンド ユーザーのデバイスに必要なストレージの量を増やします。

iOS 8 を初めて使用する開発者は、自動レイアウトとサイズ クラスを使用して、すべてのデバイス、解像度、向きに対応する動的起動画面を作成する単一のアトミック .xib ファイルを Xcode に作成できます。 これにより、開発者が必要なすべてのイメージ資産を作成して維持するために必要な作業量が削減されるだけでなく、アプリケーションのインストール済みバンドルのサイズが大幅に削減されます。

動的起動画面には、次の制限事項と考慮事項があります。

  • クラスのみを UIKit 使用します。
  • または UIViewController オブジェクトである単一のルート ビューをUIView使用します。
  • アプリケーションのコードに接続しないでください ( ActionsOutlet を追加しないでください)。
  • オブジェクトを追加 UIWebView しないでください。
  • カスタム クラスは使用しないでください。
  • ランタイム属性は使用しないでください。

上記のガイドラインを念頭に置いて、既存の Xamarin iOS 8 プロジェクトに動的起動画面を追加する方法を見てみましょう。

次の操作を行います。

  1. Visual Studio for Mac開き、ソリューションを読み込んで動的起動画面を追加します。

  2. ソリューション エクスプローラーでファイルをMainStoryboard.storyboard右クリックし、[Xcode インターフェイス ビルダー>開く] を選択します。

    Xcode インターフェイス ビルダーで開く

  3. Xcode で、[ファイル>] [新しい>ファイル] の順選択します。

    [ファイル]、[新規作成] の順に選択します

  4. [ iOS>ユーザー インターフェイス>の起動画面 ] を選択し、[ 次へ ] ボタンをクリックします。

    iOS/ユーザー インターフェイス/起動画面を選択する

  5. ファイル LaunchScreen.xib に名前を付け、[ 作成 ] ボタンをクリックします。

    ファイルに LaunchScreen.xib という名前を付けます

  6. グラフィック要素を追加し、レイアウト制約を使用して特定のデバイス、向き、画面サイズに合わせた配置を行って、起動画面のデザインを編集します。

    起動画面のデザインの編集

  7. LaunchScreen.xib に対する変更を保存します。

  8. [ アプリケーション ターゲット ] と [ 全般 ] タブを選択します。

    [アプリケーション ターゲット] と [全般] タブを選択します

  9. [ Info.plist の選択 ] ボタンをクリックし、Xamarin アプリの を選択 Info.plist し、[ 選択 ] ボタンをクリックします。

    Xamarin アプリの Info.plist を選択します

  10. [ アプリ アイコンと起動イメージ ] セクションで、[ 起動画面ファイル ] ドロップダウンを開き、上記で作成した を LaunchScreen.xib 選択します。

    LaunchScreen.xib を選択する

  11. ファイルへの変更を保存し、Visual Studio for Macに戻ります。

  12. Visual Studio for Macが Xcode との変更の同期を完了するまで待ちます。

  13. ソリューション エクスプローラーで、[リソース] フォルダーを右クリックし、[Add Add Files...]\(ファイルの追加>\) を選択します。

    [追加]、[ファイルの追加]の順に選択します。

  14. 上記で作成したファイルを LaunchScreen.xib 選択し、[ 開く ] ボタンをクリックします。

    LaunchScreen.xib ファイルを選択します

  15. アプリケーションをビルドします。

動的起動画面のテスト

Visual Studio for Macで、iPhone 4 Retina シミュレーターを選択し、アプリケーションを実行します。 動的起動画面は、正しい形式と向きで表示されます。

垂直方向に表示される動的起動画面

Visual Studio for Macでアプリケーションを停止し、iPad iOS 8 デバイスを選択します。 アプリケーションを実行すると、このデバイスと向きの起動画面が正しく書式設定されます。

水平方向に表示される動的起動画面

Visual Studio for Macに戻り、アプリケーションの実行を停止します。

iOS 7 の使用

iOS 7 との下位互換性を維持するには、iOS 8 アプリケーションで通常どおり通常 Default.png のイメージ資産を含めるだけです。 iOS は以前の動作に戻り、iOS 7 デバイスで実行するときに、これらのファイルをスタートアップ画面として使用します。

Xamarin での動的起動画面の実装を確認するには、このドキュメントに添付されている 動的起動画面 のサンプル iOS 8 アプリケーションを参照してください。

まとめ

この記事では、サイズ クラスと、iPhone と iPad デバイスのレイアウトに与える影響について簡単に説明しました。 特徴、特性環境、および特徴コレクションが Size クラスと連携して統合インターフェイスを作成する方法について説明しました。 アダプティブ ビュー コントローラーと、統合インターフェイス内のサイズ クラスの使用方法について簡単に説明しました。 Xamarin iOS 8 アプリケーション内の C# コードから、サイズ クラスと統合インターフェイスを完全に実装する方法について説明しました。

最後に、この記事では、すべての iOS 8 デバイスのスタートアップ画面として表示される 1 つの動的起動画面の作成の基本について説明しました。