iOS 9(Swift)のAdaptive Split View ControllerおよびPopover。 パート2





これは、iPadおよびiPhone上のiOS 9のSplit View ControllerおよびPopoverの適応動作に関連するチュートリアルの 2番目の部分であり、 Size Classesコンセプトによって可能になりました。 トレーニングは、クラウドベースの写真ストレージサービスであるFlickr.comサーバーと連携する実用的なアプリケーションをSwiftで作成することで構成されています。



最初の部分は、 マスターの複雑さが異なる、Adaptive Split View ControllerPopoverを使用する開発者の観点からの5つの興味深いケースをリストしています。 詳細はどこでも同じ-Navigation Controllerに挿入され、写真画像を表示するように設計された唯一のImage View Controller



1.クラシックバージョン: マスターの 1つの要素、 Navigation Controllerに挿入(多くの場合、これはTable View Controllerです



2. Navigation Controllerに挿入された多くのTable View Controllerアイテム



3. マスターとしてのTab Bar Controller



4.異なるサイズクラスのデバイスの異なるUIおよび異なるユーザークラスのケースはここでは考慮されませんが、アイデアは「iOS 9の2つのストーリーボードを備えた適応インターフェイス」で見つけることができます。



5.アダプティブポップオーバー



最初の部分では、Swiftで基本的な実験アプリケーションを作成し、ケース1〜2に拡張しました。 この記事では、実験アプリケーションをさらに複雑にし、ケース3および5に拡張します。すべてのオプションのコードはGithubにあります。





3.マスターとしてのTab Bar Controller



アプリケーションを改善し、 NSUserDefaults



ストレージ内の「最近表示された」写真を記憶する(つまり、このアプリケーションの起動時に絶えず保存する必要がある)ユーザーに別のタブBar Controllerで表示する機会を提供します。 これを行うには、以前のAdaptiveSplitViewController2Swiftアプリケーションに基づいて、新しいAdaptiveSplitViewController3Swiftアプリケーションを作成し、 Tab Bar Controllerをストーリーボードに追加し、それに付随するView Controllerを削除し、代わりにNavigation Controllerに挿入されたカメラマンと「最近の」ものを表示するように設計された別のResents画面フラグメントを接続します写真とNavigation Controllerにも挿入:





アプリケーションを起動し、iPadですべてが正常に動作することを確認します。 コンパクト幅モードのすべてのiPhoneでは、 ImageViewController



を使用した画像の画像がタイトル付きで画面に表示されますが、ナビゲーションバーや追加のボタンは表示されません。 しかし、最も悲しいことは、この画面からどこにも移動できないことです。







SplitViewControllerDetailのモーダルビューを提供するTab Bar Controllerを介してMasterを制御するため、 SplitViewControllerImageViewController



MasterNavigation Controllerのスタックに配置できないことを示唆しています。 この状況を修正するために、 マスターの Navigation ControllerスタックにImageViewController



し、 コンパクト幅モードのshowDetailViewController



デリゲートのshowDetailViewController



メソッドでこれを実行できます。

まず、 コンパクト幅モードを定義し、 Masterの Navigation Controller取得します。 次に、 ImageViewController



を抽出し、それをMasterの Navigation Controllerスタックに入れて、画面に表示します。



AppDelegate.swift





true



を返すということは、 SplitViewController



SplitViewController



制御してはならないことを意味します。 これで、 コンパクト幅デバイスの写真の画像が正しく表示されます。NavigationControllerのように戻るボタンとスライドを使用すると、モーダルに表示されずに離れることができません。







しかし、 ImageViewController



Masterの Navigation Controllerスタックに追加したので、ランドスケープモードに切り替えるときにMasterで ImageViewController



を取得できます。もちろん、これは受け入れられませんImageViewController



Detailの代わりにのみ表示されるためです:







したがって、ランドスケープモードに切り替えるときは、 マスターの Navigation ControllerスタックからImageViewController



を削除する必要があります。



AppDelegate.swift





削除しimageURL



ばかりのImageViewController



imageURL



の知識を使用して、写真のリスト内の対応する行を構成できます。



AppDelegate.swift





ストーリーボードから詳細を復元し、結果の写真でMdelを構成します。



AppDelegate.swift





その結果、iPhone 6以降のポートレートモードからランドスケープモードへの移行など、iPhoneの状況は回復します。





「Resents」タブ、いわゆる「最近の」写真について少し話しましょう。 このビューコントロール rは、ユーザークラスResentsTVC



によって提供されますResentsTVC











ResentsTVC



クラスはResentsTVC



クラスを継承し、その唯一の機能はNSUserDefaults



から写真のリストを読み取ることです。

ResentsTVC.swift





コードは2行だけで完了しました。以下に、なぜこれほど単純なのかを示します。

NSUserDefaults



相互作用NSUserDefaults



、特別なResentsDefault



クラスと計算されたvar resentsPhotos



プロパティを使用して編成されます。



ResentsDefault.swift





これは、 String



型のキーとString



型の値を持つ辞書の配列です。 さらに、このプロパティの{get}



NSUserDefaults



からデータを読み取り、 {set}



NSUserDefaults



書き込みNSUserDefaults



NSUserDefaults



は本質的に、アプリケーションの実行間でプロパティリストデータを永続的に保存するための非常に小さなデータベースであることに注意してください。 Flickr.comサーバーから受信した写真に関する情報を格納するための内部データ構造NSDictionarys



Photo



struct



であり、 NSDates



NSStrings



NSDates



NSDictionarys



いずれでもない[Photo]



配列を選択しました。 NSUserDefaults



保存に[Photo]



を使用することはできません。これはプロパティリストではないためです。

辞書の配列[[String : String]]



を使用して、 プロパティリストデータであるNSUserDefaults



にFlickrの写真に関するデータを格納しますが、もちろんPhoto



[[String : String]]



に変換する必要があります。



DataModel.swift





NSUserDefaults



との相互作用をResentsDefault



クラスには、 パブリックAPIとして2つのプロパティがあります

var addedPhoto = Photo?



NSUserDefaults



に追加する写真、

var resentsPhotos: [[String : String]]



- NSUserDefaults



保存されている写真に関する情報を含む辞書の配列:



ResentsDefault.swift





NSUserDefaults



ストレージでの作業は、 addedPhoto



を既存のストレージに追加するという事実から始まります。これは、1行のコードとresentsPhotos



ヘルパー関数で行われます。この関数は、 NSUserDefaults



NSUserDefaults



に保存された写真resentsPhotos



写真のresentsPhotos



配列を追加しNSUserDefaults





addPhoto (photo, inDefaultsPhotos: resentsPhotos)





resentsPhotos



を補助関数の入力パラメーターとして使用すると、この計算されたプロパティに対して{get}



トリガーされ、 resentsPhotos



NSUserDefaults



ストレージからデータが読み取られます。 次に、 resentsPhotos



配列の最初に、新しい写真photo



を最も「最近」として追加します。



ResentsDefault.swift





結果の配列はresentsPhotos



再び割り当てられresentsPhotos





resentsPhotos = addPhoto (photo, inDefaultsPhotos: resentsPhotos)





、つまり{set}



がこれに対して機能することを意味し、計算されたプロパティと更新された配列がNSUserDefaults



リポジトリに書き込まれます。

NSUserDefaults



メカニズムNSUserDefaults



非常に少量のデータを保存するように設計されているため、 ResentPhotoAmount



定数で指定された写真の数(この場合は20)のみに制限します。

NSUserDefaults



ストレージで写真情報を記録するのに最適な場所について考えてみましょう。 ユーザーが写真を選択した場合、その情報をNSUserDefaults



に入れる必要があります。これはprepareForSegue



クラスのprepareForSegue



メソッドで行うのが最善prepareForSegue



が、このクラスはより一般化したままにします(他の目的で必要になる場合があります)。 したがって、 PhotosSavedNSUserDefaults



クラスのサブクラスである新しいPhotosSavedNSUserDefaults



クラスのNSUserDefaults



に写真情報を記録することに関連する新しい機能を投稿します。



PhotosSavedNSUserDefaults.swift





ストーリーボード上のFlickr写真画面フラグメントのカスタムとして、新しいPhotosSavedNSUserDefaults



クラスを正確に設定する必要があります。







しかし、 ResentsTVC



クラスに戻り、「最近の」写真とResents画面の断片を提供します。 そのタスクは、 NSUserDefaults



から「最近の」写真に関する情報を回復することであり、このために1行のコードを使用しました。



ResentsTVC.swift





この行を、 JustPostedFlickrPhotosTVC



からも継承する別のJustPostedFlickrPhotosTVC



クラスの同じ行と比較すると:



JustPostedFlickrPhotosTVC.swift





次に、同じ.flatMap(Photo.init)



コンストラクトが表示されます。 最初のケースではNSUserDefaults



から回復するときに[String : String]



入力され、2番目のケースではFlickrサーバーからデータを読み取るときに[String : AnyObject]



ます。 コンパイラーは、実行するPhoto



イニシャライザーをどのように知るのですか? 結局のところ、それらの2つがありますか?



DataModel.swift





Swiftでは、 struct



構造体は、入力パラメーターが異なる場合のみ、複数の初期化子を持つことができます。 私たちの場合、そのうちの2つがあります。



ここでは、入力パラメーターのタイプに応じて、タイプの推論と関数のオーバーロードのメカニズムが機能します。 したがって、 struct Photo



正しい初期化子struct Photo



呼び出されます。

結論: Table Bar ControllerMasterとしてSplit View Controllerの適応動作を保証するには、 showDetailViewController



デリゲートのseparateSecondaryViewControllerFromPrimaryViewController



showDetailViewController



およびshowDetailViewController



メソッドを使用する必要があります。

コードはGithub - AdaptiveSplitViewController3Swiftアプリケーションにあります。



4.レスポンシブポップオーバー



以前は、 PopoverはiPadでしか表示できませんでしたが、iOS 8以降では、いわゆる「適応」バージョンのポートレートモードとランドスケープモードの両方でiPhoneにも表示されます(詳細は後述)。 Popoverの概念は変わりませんUIViewController



内に表示されるコンテンツとしてView Controllerが必要ですが、 Popover自体はUIViewController



はありません。 これは、いわゆるPopover Presentation Controllerメカニズムを使用して画面に表示されます。

実験用アプリケーションを引き続き使用し、ストーリーボードに別の画面フラグメントを追加します。これにより、選択した写真の画像のURLが Popoverの 「ウィンドウ」に表示されます。 これを行うには、 AdaptiveSplitViewController2Swiftアプリケーション(多数のTable View Controllerマスターとする )に基づいて、新しいAdaptiveSplitViewController4Swiftアプリケーションを作成し、左側の「URL」ボタンをImage View Controller画面フラグメント(写真の画像を表示)のナビゲーションバーに追加しタイプがPopoverとして表示します。 これで、ユーザーインターフェイスは次のようになりました。







Popoverに関しては、 MVC自体ではありませんが、 PopoverとしてPresentタイプのセグエを使用して、 表示するView Controllerの外観をトリガーすることは興味深いです。

Present as Popoverタイプのセグエを作成するに 、通常どおり、 CTRLView Controllerにドラッグします。また、 prepareForSegue



メソッドを実行することもできます。

タイプPresents of Popoverの セグエをインストールしたら、





「ウィンドウ」のサイズ、つまりトップビューのサイズを調整することが可能になります







セグエの識別子「Show URL」を設定し、 ImageViewController



prepareForSegue



メソッドを追加しImageViewController







ImageViewController.swift





Popoverの セグエを準備するときは、いくつかの追加機能に注意する必要があります。 その1つは、 prepareForSegue



内でUIPopoverPresentationController



と呼ばれるものを取得し、 Popoverプレゼンテーションを構成できることです。 たとえば、 Popoverを何かの左側 「ポップアップ」させたくないが、 Popoverを常に何かの右側 「ポップアップ」させたいと言うことができます。 すべてを管理できます。 さらに、 prepareForSegue



メソッドで、自分をデリゲートとして定義できます。



ImageViewController.swift





次に、 UIPopoverPresentationControllerDelegate



プロトコルを確認します。



ImageViewController.swift





そして、 UIPopoverPresentationControllerDelegate



.None



返されるUIPopoverPresentationControllerDelegate



デリゲートメソッドを実装することにより、適応動作を「オフ」にします。 UIPopoverPresentationControllerDelegate



、iPhoneでPopover適応を「拒否」します。



ImageViewController.swift





そして、 Popoverを iPhoneの小さな「ウィンドウ」 として表示するのに必要なことはそれだけです。 通常、この方法はブログにあります。

しかし、実験アプリケーションでは、これを少し異なる方法で実装しますImageViewController



クラスは、写真画像URLの表示方法に依存せず、写真画像URLを表示するTextView



を含む画面フラグメント自体は自動調整するという考え方に準拠しています。

この2番目の方法を見てみましょう。

写真画像のURLの表示は、カスタムクラスURLViewController



によって提供されます

URLViewController



クラスのモデルはプロパティです

var url : NSURL?





「ライフサイクル」 viewDidLoad



メソッドと同様に、インストールされると、ユーザーインターフェイスはupdateUI()



メソッドを使用して更新されます。 このクラスでPopover構成全体を直接実行するため、 URLViewController



クラスはUIPopoverPresentationControllerDelegate



プロトコルを確認します。







他の誰よりも先に呼び出されるawakeFromNib



“ lifecycle” awakeFromNib



では、プレゼンテーションスタイルを.Popover



設定し、 UIPopoverPresentationControllerDelegate



プロトコルのデリゲートとして自分自身を指定します。



URLViewController.swift





UIPopoverPresentationControllerDelegate



を使用して、 PopoverがiPhoneでどのように適応するかに影響を与えることができます。 iPadのポップオーバーは、従来の方法で「ポップアップ」します-小さなウィンドウの形。 iPhoneでは、 Popoverは小さなウィンドウではなく、フルスクリーンのモーダルウィンドウに適応します。 iPhoneの小さなもののように「ポップアップ」しません。 なんで? iPhoneの画面はずっと小さく、「ポップアップ」が本当に大きい場合、画面サイズに合わせる方法がないかもしれません。 しかし、画面全体でモーダルを想像すると、画面のサイズと正確に一致します。 Split View ControllerNavigation Controllerが自動的に適応するように、iOSはこの適応を自動的に行います。 しかし、 UIPopoverPresentationControllerDelegate



デリゲートを使用すると、この適応に取り組むことができます。それが私たちのすることです。

iOS 9では、 Popoverがプレゼンテーションを作成しようとすると、 PopoverをiPhoneに「適応」させる方法を尋ねられます。 デフォルトでは、これはフルスクリーンのモーダルビュー( .FullScreen



return)ですが、 UIModalPresentationStyle.None



を使用したいと言うことができます。これは、自動適応がないことを意味します。 つまり、iPhoneでのプレゼンテーションはiPadでのプレゼンテーションとまったく同じになります。 小さなPopoverにとってこれは非常に理にかなっています。 UIPopoverPresentationControllerDelegate



を返すUIModalPresentationStyle.None



デリゲートUIPopoverPresentationControllerDelegate



実装することにより、「適応」動作を「オフ」にすることができUIModalPresentationStyle.None







URLViewController.swift





Popoverの最後の非常に重要なことは、ポップアップウィンドウのサイズです。

MVCにぴったり合うサイズの「ポップアップ」ウィンドウが表示されたら、本当に気に入っています。 MVCのサイズは異なる可能性があるためです。 いずれにせよ、あなたは本当にそのサイズを制御したいと思います。 オブジェクト指向の世界では、システムはPopoverにあるMVCにこのMVCが好むサイズを尋ねますか? どのサイズになりたいですか? それが本当であるので、 MVC自体だけがどのサイズが優先されるかを知ることができます。 しかし、 Popoverにはいくつかの制限があるため、これは推奨事項にすぎません。 たとえば、 ポップオーバーは特定の場所でのみ画面に表示できます。画面は十分に大きくなければならず、矢印には特定の方向を指定できます。 Popoverにはこの種の制限多くあります。

しかし、彼はまだMVCに尋ねます。

UIViewController



は特別なプロパティがあります:

var preferredContentSize: CGSize





このプロパティをオーバーライドして、適切なサイズを返すことができます。 希望のサイズが常に同じ場合は、単純に設定できます。 内容に基づいて優先サイズを計算する必要がある場合は、次のように実行できます。



URLViewController.swift





その結果、 コンパクト幅デバイスでも通常 デバイスと同じ小さな「ウィンドウ」が表示されます。







iPadでポートレートモードで動作するPopoverには1つの問題があります。 iPadでポートレートモードで特定の写真のURLを表示する場合、ナビゲーションパネルの左側にあるFlickr Photographersをクリックして、別の写真家と別の写真を選択します...前のURLが画面に残っていることがわかりますが、 Popoverの外側をクリックすると、 Popoverは終了します。







画像はすでに変更されており、 Popoverの外側の画像自体をクリックするまでURLは古いままです。

答えは、「URL」ボタンがある同じパネルをクリックすると、そこにあるすべてのものとやり取りすることができます。つまり、ボタンをクリックするとポップオーバーは消えません。 特に、 Flickr Photographersの戻るボタンをクリックすると、 この状況はpassthroughViews



関連していpassthroughViews



。 ナビゲーションバー全体がpassthroughViews



一部であり、本当に悪いことは、リスト内の別の写真をクリックすると、写真の写真が更新されますがURLのある Popoverは更新されないことです。 画面には引き続き古い写真のURLが含まれます 。 これは本当にひどいです。

コードでこの問題を次のように解決します。 誰かが新しいimage



インストールするたびに、私は持っているポップオーバーをすべて消します。



ImageViewController.swift





今、状況は改善されました







おわりに コンパクト幅デバイスで「小さなウィンドウ」としてPopoverを表示するには、フルスクリーンモーダルウィンドウの形式でのコンパクト幅デバイス用のPopoverの適応型自動表示をキャンセルする必要があります。 これは、 adaptivePresentationStyleForPresentationController



メソッドを使用して実行できます。

UIPopoverPresentationControllerDelegate



委任します。 UIModalPresentationStyle.None



、値UIModalPresentationStyle.None



を返します。

コードはGithub - AdaptiveSplitViewController4Swiftアプリケーションにあります。



All Articles