iPhone视图将显示不触发


116

我读过许多有关职位有问题的人viewWillAppear,当你不创建视图层次只是权利。我的问题是我不知道这意味着什么。

如果我创建一个RootViewControlleraddSubView在该控制器上调用,我希望为viewWillAppear事件连接添加的视图。

有没有人有一个复杂的程序化视图层次结构示例,可以成功地viewWillAppear在每个级别接收事件?

苹果的文档状态:

警告:如果属于视图控制器的视图直接添加到视图层次结构中,则视图控制器将不会收到此消息。如果在视图层次结构中插入视图或将视图添加到视图层次结构,并且该视图具有视图控制器,则应直接将此消息发送给关联的视图控制器。未能发送该视图控制器此消息将阻止显示任何关联的动画。

问题在于他们没有描述如何做到这一点。“直接”是什么意思?您如何“间接”添加视图?

我对Cocoa和iPhone相当陌生,因此,如果除了基本的Hello World垃圾邮件之外还有苹果的有用示例,那将很好。


我遇到了这个问题,直到我意识到我通常误解了UIViewController子类的预期用途。看看这个问题。 stackoverflow.com/questions/5691226/...
averydev

7
请当心!!!在iOS 5上不再适用!调用viewWillAppear中和viewDidAppear自动
维勒姆·库尔兹

Answers:


55

如果您使用导航控制器并设置其委托,则不会调用view {Will,Did} {Appear,Disappear}方法。

您需要改用导航控制器委托方法:

navigationController:willShowViewController:animated:
navigationController:didShowViewController:animated:

2
我没有设置导航控制器的委托,但该方法没有被调用。无论如何,我先进行设置,然后使用您上面提到的方法。谢谢。
Dimitris

我看到同样的事情,季米特里斯
JKP

7
我只是在iOS4的和iOS5的测试,这一点:这不是真的:设置navigationController的委托,然后推以将火viewWillAppear中:等
DaGaMs

雨燕3:func navigationController(_ NavigationController:UINavigationController,willShow viewController:UIViewController,animation:Bool){} func navigationController(_ NavigationController:UINavigationController,didShow viewController:UIViewController,animation:Bool){}
Naloiko Eugene

28

我遇到了同样的问题。只需将viewWillAppear消息发送到视图控制器,然后再将其添加为子视图即可。(有一个BOOL参数告诉视图控制器是否正在动画显示。)

[myViewController viewWillAppear:NO];

在节拍器示例中查看RootViewController.m。

(实际上,我发现Apple的示例项目很棒。比HelloWorld多了很多;)


3
实际上,将其添加到子视图之后,应该调用viewWillAppear。否则,将不会连接IBOutlets / IBAction。
4thSpace,2009年

2
是的,之后。从XIB创建的子视图,未调用viewWillAppear。自己叫它,一切正常。
JOM

谢谢!对我来说就是这样。我是通过手动添加子视图的[scrollView addSubview:controller.view];。之后我添加了行[controller viewWillAppear:NO];,瞧!像魅力一样工作。
罗伯·S。2010年

很有可能,这是因为您的UIViewController正在控制一个视图,该视图是另一个UIViewController控制的视图的子视图。这不是预期的设计模式。有关更多说明,请查看此帖子。stackoverflow.com/questions/5691226/...
averydev

6
请当心!!!在iOS 5上不再适用!自动调用viewWillAppear和viewDidAppear。如果您手动调用它,它将被调用两次。
维勒姆·库尔兹

18

我终于找到了解决该问题的方法!

UINavigationControllerDelegate

我认为要点是将导航控件的委托设置为它所在的viewcontroller并实现UINavigationControllerDelegate,这是两种方法。辉煌!我很激动,终于找到了解决方案!


如何将rootviewcontroller分配为navigationcontroller的委托?
Gargo 2012年

1
它不起作用!尝试最小化应用程序并将其最大化
Vyachaslav Gerchicov

8

我只是有同样的问题。在我的应用程序中,我有2个导航控制器,并且在一种情况下推同一个视图控制器,而在另一种情况下却不起作用。我的意思是在第一个中推送完全相同的视图控制器时UINavigationControllerviewWillAppear但在第二个导航控制器中推送时未调用。

然后我碰到了这篇文章,UINavigationController应该调用viewWillAppear / viewWillDisappear方法

并意识到我的第二个导航控制器确实进行了重新定义viewWillAppear。筛选代码表明我没有打电话

[super viewWillAppear:animated];

我添加了它,它起作用了!

该文档说:

如果重写此方法,则必须在实现中的某个时刻调用super。


这里也是一样。不叫超级迷住了。
olivaresF 2012年

5

我一直在使用导航控制器。当我想下降到另一个数据级别或显示我的自定义视图时,请使用以下命令:

[self.navigationController pushViewController:<view> animated:<BOOL>];

当我这样做时,我确实会viewWillAppear触发该函数。我想这被称为“间接”,因为我addSubView自己没有在调用实际方法。我不知道这是否100%适用于您的应用程序,因为我无法确定您是否正在使用导航控制器,但是也许它将提供一个提示。


5

谢谢iOS 13。

ViewWillDisappearViewDidDisappearViewWillAppearViewDidAppear不会被调用iOS上13呈现视图控制器,它使用不覆盖整个屏幕一个新的模式呈现上。

学分归Arek Holko所有。他真的救了我。

在此处输入图片说明


4

首先,标签栏应该在根目录级别,即添加到窗口中,如Apple文档中所述。这是正确行为的关键。

其次,您可以使用UITabBarDelegate/ UINavigationBarDelegate手动转发通知,但是我发现要使整个视图调用层次结构正常工作,我要做的就是手动调用

[tabBarController viewWillAppear:NO];
[tabBarController viewDidAppear:NO];

[navBarController viewWillAppear:NO];
[navBarController viewDidAppear:NO];

..仅在设置相应控制器上的视图控制器之前(分配之后)。从那时起,它在其子视图控制器上正确调用了这些方法。

我的层次结构是这样的:

window
    UITabBarController (subclass of)
        UIViewController (subclass of) // <-- manually calls [navController viewWill/DidAppear
            UINavigationController (subclass of)
                UIViewController (subclass of) // <-- still receives viewWill/Did..etc all the way down from a tab switch at the top of the chain without needing to use ANY delegate methods

第一次在tab / nav控制器上调用上述方法可确保所有事件均已正确转发。它使我无需从UINavigationBarDelegate/ UITabBarControllerDelegate方法手动调用它们。

旁注:奇怪的是,当它不起作用时,私有方法

- (void)transitionFromViewController:(UIViewController*)aFromViewController toViewController:(UIViewController*)aToViewController 

..在正常的实现中,您可以从调用堆栈中看到..通常会调用viewWill/Did..方法,但是直到我执行了上述操作(即使它被调用)才开始调用。

我认为,非常重要的一点UITabBarController是,它处于窗口级别,并且文档似乎对此进行了备份。

希望这很清楚,很高兴回答其他问题。


3

由于没有答案被接受,人们(像我一样)落在这里,所以我给出了自己的变化。尽管我不确定那是最初的问题。当导航控制器作为子视图添加到另一个视图时,您必须像这样自己调用viewWillAppear / Dissappear等方法:

- (void) viewWillAppear:(BOOL)animated
{
    [super viewWillAppear:animated];

    [subNavCntlr viewWillAppear:animated];
}

- (void) viewWillDisappear:(BOOL)animated
{
    [super viewWillDisappear:animated];

    [subNavCntlr viewWillDisappear:animated];
}

只是为了使示例完整。这段代码显示在我创建并添加导航控制器到放置在视图中的视图的ViewController中。

- (void)viewDidLoad {

    // This is the root View Controller
    rootTable *rootTableController = [[rootTable alloc]
                 initWithStyle:UITableViewStyleGrouped];

    subNavCntlr = [[UINavigationController alloc]   
                  initWithRootViewController:rootTableController];

    [rootTableController release];

    subNavCntlr.view.frame = subNavContainer.bounds;

    [subNavContainer addSubview:subNavCntlr.view];

    [super viewDidLoad];
}

.h看起来像这样

@interface navTestViewController : UIViewController <UINavigationControllerDelegate> {
    IBOutlet UIView *subNavContainer;
    UINavigationController *subNavCntlr;
}

@end

在nib文件中,我有一个视图,在此视图下有一个标签,图像和放置控制器的容器(另一个视图)。这是它的外观。我不得不争一些东西,因为这对客户来说是可行的。

替代文字


3

通过调用“直接”添加视图 [view addSubview:subview]。通过交换子视图的选项卡栏或导航栏等方法“间接”添加视图。

每次致电时[view addSubview:subviewController.view],您都应该致电[subviewController viewWillAppear:NO](或视情况而定选择YES)。

当我为游戏的子屏幕实现自己的自定义根视图管理系统时,遇到了这个问题。手动添加对viewWillAppear的调用解决了我的问题。


3

正确的方法是使用UIViewController包含API。

- (void)viewDidLoad {
     [super viewDidLoad];
     // Do any additional setup after loading the view.
     UIViewController *viewController = ...;
     [self addChildViewController:viewController];
     [self.view addSubview:viewController.view];
     [viewController didMoveToParentViewController:self];
}

这绝对是正确的现代解决方案(iOS 9,8,7)。另外,如果您要即时更改嵌入式视图控制器,则需要调用[viewController willMoveToParentViewController:nil]; [viewController.view removeFromSuperview]; [viewController removeFromParentViewController];
Eli Burke

1
在这种情况下,viewWillAppear:可能仍不被称为
Vyachaslav Gerchicov

2

我将此代码用于推送和弹出视图控制器:

推:

[self.navigationController pushViewController:detaiViewController animated:YES];
[detailNewsViewController viewWillAppear:YES];

流行:

[[self.navigationController popViewControllerAnimated:YES] viewWillAppear:YES];

..并且对我来说很好。


2

一个非常常见的错误如下。您有一个视图,UIView* a另一种视图UIView* b。您将b添加到a作为子视图。如果您尝试在b中调用viewWillAppear,它将永远不会被触发,因为它是a的子视图


2

iOS 13将我的应用放在这里。如果您注意到iOS 13上的行为发生了变化,请在推送之前进行以下设置:

yourVC.modalPresentationStyle = UIModalPresentationFullScreen;

您可能还需要在.storyboard中的“属性”检查器中进行设置(将“演示”设置为“全屏”)。

这将使您的应用程序像在以前的iOS版本中一样运行。


1

我对此不是100%肯定,但是我认为将视图添加到视图层次结构直接意味着调用-addSubview:视图控制器的视图(例如[viewController.view addSubview:anotherViewController.view]),而不是将新的视图控制器推入导航控制器的堆栈中。


1

我认为添加子视图并不一定意味着该视图将出现,因此并没有自动调用该类的方法


1

我认为它们“直接”的含义是通过与xcode“导航应用程序”模板相同的方式进行连接,该模板将UINavigationController设置为应用程序UIWindow的唯一子视图。

使用该模板是我能够通过在UINavigationController中推送/弹出这些控制器时在对象ViewControllers上调用Will / Did / Appear / Disappear方法的唯一方法。答案中的其他解决方案都没有对我有用,包括在RootController中实现它们并将它们传递给(子级)NavigationController。仅在显示/隐藏顶级VC,我的“登录”和navigationVC而不是导航控制器中的子VC时,才在RootController中调用这些函数(will / did / appear / disappear)。将它们“传递”到Nav VC。

我最终使用UINavigationController的委托功能来查找需要我的应用程序中具有后续功能的特定转换,并且该转换确实可行,但是要使“消失”和“出现”功能都得到“模拟”,还需要做更多的工作。

同样,今天经过几个小时不停地解决这个问题,让它正常工作也是一个原则问题。使用自定义RootController和子导航VC的任何工作代码段将不胜感激。


1

万一这对任何人都有帮助。我有一个类似的问题,就是我ViewWillAppear没有开火UITableViewController。经过大量的试验,我意识到问题UINavigationController是控制我的那个UITableView不在根视图上。一旦我解决了它,它现在就像冠军。


您能分享一下您是如何做到的吗?
Brabbeldas

1

我自己只是遇到了这个问题,花了3个完整小时(其中2个是谷歌搜索)来解决它。

事实证明有帮助的是,只需从设备/模拟器中删除该应用程序,进行清理,然后再次运行

希望能有所帮助


1
[self.navigationController setDelegate:self];

将委托设置为根视图控制器。


1

对于Swift。首先创建协议以调用要在viewWillAppear中调用的协议

protocol MyViewWillAppearProtocol{func myViewWillAppear()}

二,创建班级

class ForceUpdateOnViewAppear: NSObject, UINavigationControllerDelegate {
func navigationController(_ navigationController: UINavigationController, willShow viewController: UIViewController, animated: Bool){
    if let updatedCntllr: MyViewWillAppearProtocol = viewController as? MyViewWillAppearProtocol{
        updatedCntllr.myViewWillAppear()
    }
}

}

第三,使ForceUpdateOnViewAppear实例成为可以访问Navigation Controller的适当类的成员,并且只要存在Navigation Controller就可以存在。例如,它可能是导航控制器的根视图控制器或创建或呈现它的类。然后尽早将ForceUpdateOnViewAppear实例分配给Navigation Controller委托属性。


0

就我而言,问题在于自定义过渡动画。设置modalPresentationStyle = .custom viewWillAppear不叫时

在自定义过渡动画类中,需要调用方法: beginAppearanceTransitionendAppearanceTransition


0

就我而言,那只是ios 12.1模拟器上的一个奇怪的错误。在真实设备上启动后消失。



0

ViewWillAppear是UIViewController类的重写方法,因此添加subView不会调用viewWillAppear,但是当您从viewController呈现push,pop,show,setFront或popToRootViewController时,将为呈现的viewController调用viewWillAppear。


0

我的问题是从segue放松时未调用viewWillAppear。答案是在视图控制器的展开序列中调用对viewWillAppear(true)的调用,然后将其返回

@IBAction func unwind(用于unwindSegue:UIStoryboardSegue,ViewController随后VC:任何){

   viewWillAppear(true)
}

-2

我不确定这是否与我解决的问题相同。
在某些情况下,方法不会以“ [self methodOne]”之类的常规方式执行。

尝试

- (void)viewWillAppear:(BOOL)animated
{
    [self performSelector:@selector(methodOne) 
           withObject:nil afterDelay:0];
}

问题根本viewWillAppear没有得到解决
Vyachaslav Gerchicov '17

-3

任何时候您都应该只激活1个UIViewController。您要操作的任何子视图都应该完全相同-subVIEWS-即UIView。

我使用一种简单的技术来管理视图层次结构,但是自从我开始以这种方式进行操作以来,还没有遇到问题。有两个关键点:

  • 一个UIViewController应该用于管理应用程序的“屏幕价值”
  • 使用UINavigationController更改视图

“屏幕的价值”是什么意思?这样做的目的有些含糊,但通常是应用程序的功能或部分。如果您的几个屏幕具有相同的背景图像,但具有不同的叠加层/弹出窗口等,则应为1个视图控制器和多个子视图。您永远不会发现自己使用2个视图控制器。请注意,如果您希望屏幕的某些区域显示在多个视图控制器中,您仍然可以在一个视图控制器中实例化一个UIView并将其添加为另一个视图控制器的子视图。

至于UINavigationController-这是你最好的朋友!关闭导航栏并为“动画”指定“否”,您可以通过一种极好的方式按需切换屏幕。如果视图控制器位于层次结构中,则可以对其进行推送和弹出,也可以准备视图控制器数组(包括包含单个VC的数组),并使用setViewControllers将其设置为视图堆栈。这使您拥有完全的自由来更改VC,同时获得了在Apple预期的模型中工作并获得所有事件等的所有优势。

这是我每次启动应用程序时都会做的事情:

  • 从基于窗口的应用程序开始
  • 添加一个UINavigationController作为窗口的rootViewController
  • 添加我想要的第一个UIViewController作为导航控制器的rootViewController的任何内容

(请注意,从基于窗口的模板开始只是个人喜好-我喜欢自己构建事物,因此我确切地知道它们是如何构建的。它应该与基于视图的模板一起正常工作)

所有事件均正确触发,基本上生活是美好的。然后,您可以将所有时间都花在编写应用程序的重要部分上,而不必为试图手动修改视图层次结构而烦恼。


激活多个视图控制器没有什么错;UIViewController具有允许构造层次结构的方法(例如[addChildViewController:])。
理查德

1
是的,现在可以了。2011年没有。当时的答案是准确的,诚然不是现在。
Nigel Flack 2013年
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.