web-dev-qa-db-ja.com

現在のView Controllerに子View Controllerを追加する

次のコードを使用して、ストーリーボードから現在のView Controllerにコードで子View Controllerを追加しようとしています:

UIStoryboard *storyboard = [UIStoryboard storyboardWithName:@"Main" bundle: nil];
LogInTutorialViewController *lvc = [[LogInTutorialViewController alloc] init];
lvc = (LogInTutorialViewController *)[storyboard instantiateViewControllerWithIdentifier:@"LogInTutorialViewControllerID"];
[self displayContentController:lvc];

- (void) displayContentController: (LogInTutorialViewController*) content;
{

    //add as childViewController
    [self addChildViewController:content];
    [content didMoveToParentViewController:self];
    [content.view setFrame:CGRectMake(0, 0, [UIScreen mainScreen].bounds.size.width, [UIScreen mainScreen].bounds.size.height)];
    [self.view addSubview:content.view];

}

ビューは少なくともシミュレータに表示されているようですが、コンソールでは多くのエラーが発生します:

 <Error>: CGContextSaveGState: invalid context 0x0. This is a serious error. This application, or a library it uses, is using an invalid context  and is thereby contributing to an overall degradation of system stability and reliability. This notice is a courtesy: please fix this problem. It will become a fatal error in an upcoming update.

また、同じ説明ですが異なるエラー:

CGContextSetLineWidth、CGContextSetLineJoin、CGContextSetLineCap、CGContextSetMiterLimit、CGContextSetFlatness、CGContextAddPath、CGContextDrawPath、CGContextRestoreGState

これらのエラーはすべて2回記録されます。

誰かが私が間違っていることを知っていますか?

また、私はいくつかの投稿を読みましたが、データを渡す前にView Controllerを割り当てて初期化することが提案されたものもありましたが、幸運なくそれを試しました。

19
Laur Stefan

didMoveToParentViewControllerは最後でなければなりません。

6
kirander

ビューを追加するためにこのコードを試さない理由は、これはシンプルで簡単だと思います。

self.loginView = [self.storyboard instantiateViewControllerWithIdentifier:@"LOGIN"];
[self addChildViewController:self.loginView];
[self.loginView.view setFrame:CGRectMake(0.0f, 0.0f, self.contentView.frame.size.width, self.contentView.frame.size.height)];
[self.contentView addSubview:self.loginView.view];
[self.loginView didMoveToParentViewController:self]; 

詳細については、これを確認してください link

27
  • Interface Builderでのコンテナの構成。

設計時に親子コンテナの関係を作成するには、下の画像に示すように、ストーリーボードシーンにコンテナビューオブジェクトを追加します。コンテナビューオブジェクトは、子ビューコントローラのコンテンツを表すプレースホルダーオブジェクトです。そのビューを使用して、コンテナ内の他のビューに対して子のルートビューのサイズと位置を設定します。

enter image description here

1つ以上のコンテナビューを持つView Controllerをロードすると、Interface Builderはそれらのビューに関連付けられた子View Controllerもロードします。適切な親子関係を作成できるように、子は親と同時にインスタンス化する必要があります。

Interface Builderを使用して親子コンテナの関係を設定しない場合は、「子View Controllerをコンテンツに追加する」の説明に従って、各子をコンテナView Controllerに追加して、プログラムでそれらの関係を作成する必要があります。

  • 子View Controllerをコンテンツに追加します。

子View Controllerをプログラムでコンテンツに組み込むには、以下を実行して、関連するView Controllerの間に親子関係を作成します。

  1. addChildViewController:コンテナビューコントローラのメソッド。このメソッドは、コンテナビューコントローラが子ビューコントローラのビューを管理していることをUIKitに伝えます。
  2. 子のルートビューをコンテナのビュー階層に追加します。このプロセスの一環として、常に子供のフレームのサイズと位置を設定することを忘れないでください。
  3. 子のルートビューのサイズと位置を管理するための制約を追加します。
  4. 子View ControllerのdidMoveToParentViewController:メソッドを呼び出します。

そのコードを次に示します。

- (void)displayContentController:(UIViewController *)content {
    [self addChildViewController:content];
    content.view.frame = [self frameForContentController];
    [self.view addSubview:self.currentClientView];
    [content didMoveToParentViewController:self];
}

Swift

func displayContentController(_ content: UIViewController?) {
if let content = content {
    addChild(content)
}
content?.view.frame = frameForContentController()
view.addSubview(currentClientView)
content?.didMove(toParent: self)

}

同じ例の詳細な説明は Apple developer programming guide にあります。

22
Piyush

Swiftのソリューション(この記事の執筆時点でのSwift 4):

//load the view controller and add as child
storyboard = UIStoryboard(name: "Main", bundle: Bundle.main)
loginVC = storyboard.instantiateViewController(withIdentifier: "LOGIN")
addChildViewController(loginVC)

//make sure that the child view controller's view is the right size
loginVC.view.frame = contentView.bounds
contentView.addSubview(loginVC.view)

//you must call this at the end per Apple's documentation
loginVC.didMove(toParentViewController: self)

ノート:

  • ストーリーボード名は「メイン」です。
  • ストーリーボードのView Controller識別子は「LOGIN」という名前です。
  • これは、ストーリーボードを使用してView Controllerのロードを作成しますが、同じことをプログラムで実行できます。ビューのフレームにアクセスしようとする前に、ビューがメモリにロードされていることを確認してください。そうしないと、クラッシュします(View Controllerをモーダルに表示するなどの操作を行います)。
8
jason z