将子视图控制器添加到UINavigationController

时间:2021-07-22 07:36:48

I'm trying to add a child view controller to a UIViewController contained in a UINavigationController with this code:

我正在尝试使用以下代码将子视图控制器添加到UINavigationController中包含的UIViewController:

- (void)buttonTapped:(id)sender
{
    MyChildController *viewController = [self.storyboard instantiateViewControllerWithIdentifier:@"MyChild"];
    [self addChildViewController:viewController];
    [self.view addSubview:viewController.view];
    [viewController didMoveToParentViewController:self];


    viewController.view.alpha = 0.0f;
    [UIView animateWithDuration:0.4 animations:^{
        viewController.view.alpha = 1.0f;
    }];
}

But this is the result:

但这是结果:

将子视图控制器添加到UINavigationController

As you can see the UINavigatioBar and the UIToolbar are still on top of the child view controller. How can I put the child view controller on top of all? I've already tried to replace the code with:

如您所见,UINavigatioBar和UIToolbar仍然位于子视图控制器之上。如何将子视图控制器置于最重要的位置?我已经尝试用以下代码替换代码:

[self.navigationController addChildViewController:viewController];
    [self.navigationController.view addSubview:viewController.view];
    [viewController didMoveToParentViewController:self.navigationController];

But in this way the viewDidAppear:animated of the viewController doesn't get called, dunno why.

但是这样viewDidAppear:viewController的动画不会被调用,dunno为什么。

3 个解决方案

#1


6  

In your first view controller, do something like this:

在您的第一个视图控制器中,执行以下操作:

- (IBAction)buttonClick:(id)sender
{
    SecondViewController *secondView = [self.storyboard instantiateViewControllerWithIdentifier:@"SecondViewController"];
    UIImage *blurryImage = [UIImage imageNamed:@"foo.jpeg"];
    secondView.imageView.image = blurryImage;
    [self.navigationController addChildViewController:secondView];
    secondView.view.frame = self.navigationController.view.frame;
    [self.navigationController.view addSubview:secondView.view];
}

Then in your second view controller, add the getter for your imageview:

然后在第二个视图控制器中,为imageview添加getter:

-(UIImageView *)imageView
{
    if( _imageView == nil )
    {
        _imageView = [[UIImageView alloc] initWithFrame:CGRectMake(0, 0, 320, 548)];
        [self.view addSubview:_imageView];
    }
    return _imageView;
}

#2


30  

@Sam's comment is correct. You need to call beginApperanceTransition:animated: and endAppearanceTransition for viewDidAppear to be triggered. The reason why UINavigationController does not call viewDidAppear when you add a child view controller is because it has overridden its container composition methods to prevent the programmer from adding a child view controller in strange places. In your case, it doesn't want your child view to cover up the navigation bar. The correct usage of a navigation controller is to have children appear under the navigation bar. Nonetheless, you can still force upon this non-standard UI by manually telling the child when it is appearing and when it has finished appearing.

@Sam的评论是正确的。您需要调用beginApperanceTransition:animated:和endAppearanceTransition来触发viewDidAppear。 UINavigationController在添加子视图控制器时不调用viewDidAppear的原因是因为它已重写其容器组合方法以防止程序员在奇怪的位置添加子视图控制器。在您的情况下,它不希望您的子视图掩盖导航栏。导航控制器的正确用法是让孩子出现在导航栏下方。尽管如此,您仍然可以通过手动告知孩子何时出现以及何时完成显示来强制使用此非标准UI。

Add a child to UINavigationController

MyChildViewController* child = [[MyChildViewController alloc] init];
[self.navigationController addChildViewController:child];
child.view.frame = self.navigationController.view.bounds;
[self.navigationController.view addSubview:child.view];
child.view.alpha = 0.0;
[child beginAppearanceTransition:YES animated:YES];
[UIView
    animateWithDuration:0.3
    delay:0.0
    options:UIViewAnimationOptionCurveEaseOut
    animations:^(void){
        child.view.alpha = 1.0;
    }
    completion:^(BOOL finished) {
        [child endAppearanceTransition];
        [child didMoveToParentViewController:self.navigationController];
    }
];

Remove a child from UINavigationController

[child willMoveToParentViewController:nil];
[child beginAppearanceTransition:NO animated:YES];
[UIView
    animateWithDuration:0.3
    delay:0.0
     options:UIViewAnimationOptionCurveEaseOut
    animations:^(void){
        child.view.alpha = 0.0;
    }
    completion:^(BOOL finished) {
        [child endAppearanceTransition];
        [child.view removeFromSuperview];
        [child removeFromParentViewController];
    }
];

#3


0  

@Pwner's answer Swift version:

@Pwner的回答Swift版本:

Add child to UINavigaitonController

let child = MyChildViewController()
self.navigationController?.addChildViewController(child)
guard let navigationController = navigationController else {
    return
}
child.view.frame = navigationController.view.bounds
child.beginAppearanceTransition(true, animated: true)
self.navigationController?.view.addSubview(child.view)
self.view.alpha = 0
UIView.animate(withDuration: 0.3, animations: {
    child.view.alpha = 1.0
}, completion: { _ in
    guard let navigationController = self.navigationController else {
        return
    }
    child.endAppearanceTransition()
    child.didMove(toParentViewController: navigationController)
})

Remove a child from UINavigationController

child.willMove(toParentViewController: nil)
child.beginAppearanceTransition(false, animated: true)
UIView.animate(withDuration: 0.3, animations: {
    child.view.alpha = 0.0
}, completion: { _ in
    guard let navigationController = self.navigationController else {
        return
    }
    child.view.removeFromSuperview()
    child.endAppearanceTransition()
    child.removeFromParentViewController()
})

#1


6  

In your first view controller, do something like this:

在您的第一个视图控制器中,执行以下操作:

- (IBAction)buttonClick:(id)sender
{
    SecondViewController *secondView = [self.storyboard instantiateViewControllerWithIdentifier:@"SecondViewController"];
    UIImage *blurryImage = [UIImage imageNamed:@"foo.jpeg"];
    secondView.imageView.image = blurryImage;
    [self.navigationController addChildViewController:secondView];
    secondView.view.frame = self.navigationController.view.frame;
    [self.navigationController.view addSubview:secondView.view];
}

Then in your second view controller, add the getter for your imageview:

然后在第二个视图控制器中,为imageview添加getter:

-(UIImageView *)imageView
{
    if( _imageView == nil )
    {
        _imageView = [[UIImageView alloc] initWithFrame:CGRectMake(0, 0, 320, 548)];
        [self.view addSubview:_imageView];
    }
    return _imageView;
}

#2


30  

@Sam's comment is correct. You need to call beginApperanceTransition:animated: and endAppearanceTransition for viewDidAppear to be triggered. The reason why UINavigationController does not call viewDidAppear when you add a child view controller is because it has overridden its container composition methods to prevent the programmer from adding a child view controller in strange places. In your case, it doesn't want your child view to cover up the navigation bar. The correct usage of a navigation controller is to have children appear under the navigation bar. Nonetheless, you can still force upon this non-standard UI by manually telling the child when it is appearing and when it has finished appearing.

@Sam的评论是正确的。您需要调用beginApperanceTransition:animated:和endAppearanceTransition来触发viewDidAppear。 UINavigationController在添加子视图控制器时不调用viewDidAppear的原因是因为它已重写其容器组合方法以防止程序员在奇怪的位置添加子视图控制器。在您的情况下,它不希望您的子视图掩盖导航栏。导航控制器的正确用法是让孩子出现在导航栏下方。尽管如此,您仍然可以通过手动告知孩子何时出现以及何时完成显示来强制使用此非标准UI。

Add a child to UINavigationController

MyChildViewController* child = [[MyChildViewController alloc] init];
[self.navigationController addChildViewController:child];
child.view.frame = self.navigationController.view.bounds;
[self.navigationController.view addSubview:child.view];
child.view.alpha = 0.0;
[child beginAppearanceTransition:YES animated:YES];
[UIView
    animateWithDuration:0.3
    delay:0.0
    options:UIViewAnimationOptionCurveEaseOut
    animations:^(void){
        child.view.alpha = 1.0;
    }
    completion:^(BOOL finished) {
        [child endAppearanceTransition];
        [child didMoveToParentViewController:self.navigationController];
    }
];

Remove a child from UINavigationController

[child willMoveToParentViewController:nil];
[child beginAppearanceTransition:NO animated:YES];
[UIView
    animateWithDuration:0.3
    delay:0.0
     options:UIViewAnimationOptionCurveEaseOut
    animations:^(void){
        child.view.alpha = 0.0;
    }
    completion:^(BOOL finished) {
        [child endAppearanceTransition];
        [child.view removeFromSuperview];
        [child removeFromParentViewController];
    }
];

#3


0  

@Pwner's answer Swift version:

@Pwner的回答Swift版本:

Add child to UINavigaitonController

let child = MyChildViewController()
self.navigationController?.addChildViewController(child)
guard let navigationController = navigationController else {
    return
}
child.view.frame = navigationController.view.bounds
child.beginAppearanceTransition(true, animated: true)
self.navigationController?.view.addSubview(child.view)
self.view.alpha = 0
UIView.animate(withDuration: 0.3, animations: {
    child.view.alpha = 1.0
}, completion: { _ in
    guard let navigationController = self.navigationController else {
        return
    }
    child.endAppearanceTransition()
    child.didMove(toParentViewController: navigationController)
})

Remove a child from UINavigationController

child.willMove(toParentViewController: nil)
child.beginAppearanceTransition(false, animated: true)
UIView.animate(withDuration: 0.3, animations: {
    child.view.alpha = 0.0
}, completion: { _ in
    guard let navigationController = self.navigationController else {
        return
    }
    child.view.removeFromSuperview()
    child.endAppearanceTransition()
    child.removeFromParentViewController()
})