独自のUIViewControllers
を持つサブビューで苦労しています。ビュー(明るいピンク色)とUIViewController
に2つのボタンがあるtoolbar
があります。最初のボタンが押されたときに青色のビューを表示し、2番目のボタンで黄色のビューを表示したい。ビューを表示したいだけなら簡単なはずです。ただし、青いビューにはテーブルが含まれるため、独自のコントローラーが必要です。それが私の最初のレッスンでした。 this SO question から始めました。テーブルのコントローラーが必要だと知りました。
それで、私はバックアップして、ここでいくつかの赤ん坊のステップを踏むつもりです。以下は、ユーティリティViewController
(メインビューコントローラー)と他の2つのコントローラー(青と黄色)を使用した簡単な開始点の写真です。 Utility ViewController
(メインビュー)が最初に表示されたときに、ピンクのビューがある場所に青(デフォルト)ビューが表示されることを想像してください。ユーザーは2つのボタンをクリックして前後に移動でき、ピンクのビューは表示されません。ピンクのビューがある場所に青いビューを移動し、ピンクのビューがある場所に黄色のビューを移動するだけです。これが理にかなっていることを願っています。
addChildViewController
を使用しようとしています。私が見てきたことから、これを行うには2つの方法があります。プログラムでstoryboard
またはaddChildViewController
のコンテナビュー。プログラムでそれをしたいです。 NavigationController
またはタブバーを使用したくありません。コントローラーを追加し、関連するボタンが押されたときに正しいビューをピンクのビューに押し込みたいだけです。
以下は私がこれまでに持っているコードです。私がやりたいのは、ピンクのビューがあるところに青いビューを表示することだけです。私が見たものから、私はただaddChildViewController
とaddSubViewができるはずです。このコードは私のためにそれをしていません。私の混乱は私を良くしています。誰かがピンクのビューがある場所に青いビューを表示するのを手伝ってくれますか?
このコードは、viewDidLoadに青色のビューを表示すること以外は何もしません。
IDUtilityViewController.h
#import <UIKit/UIKit.h>
@interface IDUtilityViewController : UIViewController
@property (strong, nonatomic) IBOutlet UIView *utilityView;
@end
IDUtilityViewController.m
#import "IDUtilityViewController.h"
#import "IDAboutViewController.h"
@interface IDUtilityViewController ()
@property (nonatomic, strong) IDAboutViewController *aboutVC;
@end
@implementation IDUtilityViewController
- (void)viewDidLoad
{
[super viewDidLoad];
self.aboutVC = [[IDAboutViewController alloc]initWithNibName:@"AboutVC" bundle:nil];
[self addChildViewController:self.aboutVC];
[self.aboutVC didMoveToParentViewController:self];
[self.utilityView addSubview:self.aboutVC.aboutView];
}
@end
-------------------------- EDIT -------------- ----------------
Self.aboutVC.aboutViewはnilです。しかし、私はそれをstoryboard
に接続しました。まだインスタンス化する必要がありますか?
最新のiOSの初期の日付のこの投稿は、通常Swift 4のような最新の構文を持っています。iOS、autolayoutなどから始めている場合は、うまくいきます。
今日のiOS「すべてがコンテナビュー」。これが今日のアプリの基本的な作成方法です。
アプリは非常に単純なため、1つのビューしかありません。ただし、その場合でも、画面上の各「モノ」はコンテナビューです。
これは簡単です...
コンテナビューをシーンビューにドラッグします。 (たとえば、UIButtonにドラッグするのと同じように。)
コンテナビューは、この画像の茶色のものです。実際にはinsideあなたのシーンビューです。
コンテナビューをシーンビューにドラッグすると、Xcodeは自動的に2つのものを与えます:
コンテナビューをシーンビュー内に取得します、そして
新品のUIViewController
を取得します。これはストーリーボードの白のどこかに座っているだけです。
2つはconnectedと「Masonic Symbol」のことです-以下で説明します!
本当に簡単です。
完了です。
これは視覚的に説明したものと同じです。
(A)
のcontainer viewに注意してください。
(B)
のcontrollerに注意してください。
Bをクリックします(AではなくBです!)。
右上のインスペクターに移動します。 「UIViewController」と表示されていることに注意してください
[] [3]
UIViewControllerである独自のカスタムクラスに変更します。
したがって、Swift class Snap
であるUIViewController
があります。
インスペクターの「UIViewController」と表示されている場所に「Snap」と入力しました。
(通常どおり、「スナップ...」と入力し始めると、Xcodeは「スナップ」を自動補完します。)
これですべてです。完了です。
そのため、クリックしてコンテナビューを追加すると、Appleは自動的にストーリーボード上にリンクされたView Controllerを提供します。
偶然にも(2017):デフォルトでUIViewController
になります。
それはばかげています。どのタイプが必要かを尋ねるべきです。たとえば、多くの場合、テーブルビューが必要です。異なるものに変更する方法は次のとおりです。
執筆時点では、Xcodeはデフォルトで
UIViewController
を提供します。代わりにUICollectionViewController
が欲しいとしましょう:(i)コンテナビューをシーンにドラッグします。 Xcodeがデフォルトで提供するストーリーボード上のUIViewControllerを見てください。
(ii)新しい
UICollectionViewController
をストーリーボードのメインの白い領域のどこかにドラッグします。(iii)シーン内のコンテナビューをクリックします。接続インスペクターをクリックします。 1つの「トリガーセグエ」があることに注意してください。 「トリガーされたセグエ」をマウスオーバーして、Xcodehighlights不要なUIViewController。
(iv)「x」をクリックして、セグエをトリガーしたdeleteを実際に削除します。
(v)トリガーされたセグエからのドラッグ(viewDidLoadが唯一の選択肢です)。ストーリーボード上で新しいUICollectionViewControllerにドラッグします。放すとポップアップが表示されます。 embedを選択する必要があります。
(vi)すべての不要なUIViewControllerを単にdeleteします。できました。
短いバージョン:不要なUIViewControllerを削除します。ストーリーボードに新しいUICollectionViewController
を配置します。コントロールドラッグ:コンテナビューの接続-トリガーセグエ-viewDidLoad、新しいコントローラー。ポップアップで[埋め込み]を選択してください。
これらのいずれか "正方形の正方形"フリーメーソンシンボルの事柄:コンテナビューをView Controllerに接続する「ベンディライン」上にあります。
「フリーメーソンのシンボル」はセグエです。
(フリーメーソンのシンボル)の()をクリックしてセグエを選択します。
右側を見てください。
あなた[〜#〜] must [〜#〜]テキスト識別子を入力してくださいセグエ用。
あなたは名前を決めます。 任意のテキスト文字列を使用できます。賢明な選択は、多くの場合「segueClassName」です。
このパターンに従うと、すべてのセグエはsegueClockView、seguePersonSelector、segueSnap、segueCardsなどと呼ばれます。
次に、そのテキスト識別子をどこで使用しますか?
次に、コード全体で、シーン全体のViewControllerで以下を実行します。
シーンに3つのコンテナビューがあるとします。各コンテナビューには、「Snap」、「Clock」、「Other」などの異なるコントローラーがあります。
最新のSwift3構文(2017)
var snap:Snap?
var clock:Clock?
var other:Other?
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if (segue.identifier == "segueSnap")
{ snap = (segue.destination as! Snap) }
if (segue.identifier == "segueClock")
{ clock = (segue.destination as! Clock) }
if (segue.identifier == "segueOther")
{ other = (segue.destination as! Other) }
}
とても簡単です。 prepareForSegue
呼び出しを使用して、コントローラーを参照する変数を接続します。
コンテナビューに配置したコントローラーに「入っている」としましょう(この例では「スナップ」)。
あなたの上にある「ボス」ビューコントローラー(例では「ダッシュ」)に到達するのはわかりにくいかもしれません。幸いなことに、これは簡単です。
// Dash is the overall scene.
// Here we are in Snap. Snap is one of the container views inside Dash.
class Snap {
var myBoss:Dash?
override func viewDidAppear(_ animated: Bool) { // MUST be viewDidAppear
super.viewDidAppear(animated)
myBoss = self.parent as? Dash
}
クリティカル:viewDidAppear
以降でのみ動作します。 viewDidLoad
では機能しません。
できました。
重要な高度なヒント:コンテナービューでのみ機能することを忘れないでください。
最近では、ストーリーボードIDを使用して、画面に新しいビューをポップするだけのことが一般的です(Android development)のように。だから、ユーザーが何かを編集したいとしましょう...
// let's just pop a view on the screen.
// this has nothing to do with container views
//
let e = ...instantiateViewController(withIdentifier: "Edit") as! Edit
e.modalPresentationStyle = .overCurrentContext
self.present(e, animated: false, completion: nil)
コンテナビューを使用する場合、IT IS GUARANTEEDDashはSnapの親ビューコントローラになります。
ただし、instantiateViewControllerを使用する場合は、CASEではありません。
非常に紛らわしいことに、iOSでは、親View Controllerは、インスタンス化したクラスに関連していません。 (Itmightは同じですが、通常は同じではありません。)self.parent
パターンはonlyコンテナビューの場合。
(instantiateViewControllerパターンで同様の結果を得るには、プロトコルとデリゲートを使用する必要があります。デリゲートは弱いリンクになることに注意してください。)
「prepareForSegue」は本当に悪い名前であることに注意する価値があります!
「prepareForSegue」は、コンテナビューの読み込みと、シーン間のセグメンテーションの2つの目的で使用されます。
しかし、実際には、シーン間でのセグエはめったにありません!ほぼすべてのアプリには、当然のことながら、多くのコンテナビューがあります。
「prepareForSegue」が「loadingContainerView」のようなものと呼ばれる場合、それははるかに理にかなっています。
一般的な状況は次のとおりです。画面上にいくつかの異なるView Controllerの1つを表示したい小さな領域がある。たとえば、4つのウィジェットの1つ。
これを行う最も簡単な方法:4つの異なるコンテナビューをすべて同じ同じ領域に配置するだけです。コードで、4つすべてを非表示にして、表示したいものをオンにします。
ストーリーボードに、4つのコンテナビューを保持する空の「ホルダー」UIViewを1つ用意します。次に、「ホルダー」をサイズ変更または移動することにより、4つすべてを一度にサイズ変更または移動できます。コードには、コンテナビューごとに1つずつ、合計4つのUIView
アウトレットがあります。上記のコード「子コントローラーへの接続方法」をコピーして貼り付け、含まれている4つのView Controllerを接続します。
SimplGyが以下に指摘するように "iOS 9の ストーリーボードリファレンス コンテナービューをさらに素晴らしいものにします。再利用可能なビュー(コントローラー)を好きな場所に定義し、どのコンテナービューからでも参照できます複数のモジュール式ストーリーボードで。」
また、かなり混乱したことに注意してください。今日では、コンテナビューに煩わされないことがよくあります。
多くの場合、単にinstantiateViewController#withIdentifier
します。
ただし、上記で説明した.parent
についての「ゴッチャ」に注意してください。コンテナビューの全体的なポイントは、親チェーンを即座にかつ簡単に保証することです。
ストーリーボードリファレンスを使用してinstantiateViewController#withIdentifier
を使用する場合、プロトコルとデリゲートをいじる必要があります(デリゲートはウィークリンクになることを思い出してください)。しかし、その後、どこでも「オンザフライ」で柔軟に使用できます。
対照的に、いわゆる「固定」を使用すると、コンテナビューは非常にシンプルになり、上で説明したように、親と子の間で即座に接続します。
2つの問題があります。まず、ストーリーボードでコントローラーを作成しているため、instantiateViewControllerWithIdentifier:
ではなくinitWithNibName:bundle:
でインスタンス化する必要があります。次に、ビューをサブビューとして追加するときに、フレームを指定する必要があります。そう、
- (void)viewDidLoad
{
[super viewDidLoad];
self.aboutVC = [self.storyboard instantiateViewControllerWithIdentifier:@"aboutVC"]; // make sure you give the controller this same identifier in the storyboard
[self addChildViewController:self.aboutVC];
[self.aboutVC didMoveToParentViewController:self];
self.aboutVC.view.frame = self.utilityView.bounds;
[self.utilityView addSubview:self.aboutVC.aboutView];
}