aks*_*h1t 21 uinavigationbar ios interactivepopgesture
进场时,我UINavigationBar
在应用程序中的标题出现了一个奇怪的问题interactivePopGestureRecognizer
.我制作了一个演示应用来展示这个bug.
UINavigationController
.FirstViewController
隐藏了导航栏,并且 interactivePopGestureRecognizer.enabled = NO;
Second
并且ThirdViewController
可以看到导航栏并启用了popgesture.使用popgesture从第二个视图返回到第一个视图时会发生错误.如果您中途拉出第二个视图然后返回第二个视图,导航标题将显示"第二个视图"(如预期的那样).但是当您转到第三个视图时,标题将不会更改为"第三个视图".然后单击第三个视图的后退按钮,导航栏将变得混乱.
请查看我的演示应用程序.任何帮助解释为什么会发生这个错误将不胜感激.谢谢!
mat*_*att 49
首先,您的示例可以大大简化.你应该删除所有的viewDidLoad
东西,因为它是一个完整的红色鲱鱼,只是使问题复杂化.在视图控制器的每次更改时,您都不应该使用pop手势识别器委托; 并且关闭和打开弹出手势识别器与示例无关(默认情况下它是打开的,并且应该保留为此示例).所以在所有三个视图控制器中删除这种东西:
- (void)viewDidLoad {
[super viewDidLoad];
if ([self.navigationController respondsToSelector:@selector(interactivePopGestureRecognizer)]) {
self.navigationController.interactivePopGestureRecognizer.enabled = NO;
self.navigationController.interactivePopGestureRecognizer.delegate = self;
}
}
Run Code Online (Sandbox Code Playgroud)
(不要删除设置的代码self.title
,尽管通过在xib
每个视图控制器的文件中执行此操作可以使事情变得更简单.)
您还可以完全摆脱其他未使用的方法,例如init...
方法和内存警报方法.
顺便说一下,另一个问题是你忘了打电话给super
你的实施viewWillAppear:
.你需要这样做.我不认为这会影响bug,但在开始尝试跟踪这些事情之前,最好遵守所有规则.
现在错误仍然存在,但我们有更简单的代码,所以我们可以开始隔离问题.
那么问题的原因是什么?我认为理解它最明显的方法是实现流行手势的运作方式.这是一个交互式视图控制器转换动画.那是对的 - 这是一部动画片.它的工作方式是弹出动画(从左侧滑动)附加到超视图层,但是speed
为0,因此它实际上不会运行.随着手势的进行,timeOffset
层的不断更新,从而出现动画的相应"帧".因此看起来你正在拖动视图,但你不是; 你只是做一个手势,动画正在以相同的速度和相同的程度进行.我在这个答案中解释了这个机制:https://stackoverflow.com/a/22677298/341994
最重要的(注意这一部分),如果手势在中间放弃(几乎肯定会是这样),则决定手势是否超过一半完成,并基于此,动画快速播放到最后(即speed
设置为类似的东西3
)或动画向后跑到开始(即speed
设置为类似的东西-3
).
现在让我们谈谈这个bug.这里有两个并发症,你不小心撞到了:
当弹出动画和弹出手势开始时,viewWillAppear:
即使视图最终可能不会出现(因为这是交互式手势并且手势可能被取消),也会调用前一个视图控制器.如果您习惯于viewWillAppear:
视图实际接管屏幕(viewDidAppear:
并被调用)后总是遵循该假设,那么这可能是一个严重的问题,因为这种情况可能不会发生.(正如Apple在WWDC 2013视频中所说,"视图将出现"实际上意味着"视图可能会出现".)
还有一组辅助动画,即与导航栏相关的所有内容 - 标题的更改(它应该淡入视图),在这种情况下,不隐藏和隐藏之间的变化.运行时尝试使用滑动视图动画协调辅助动画集.但是,当隐藏或显示栏时,您通过调用无动画来实现这一点.
因此,正如您已经被告知的那样,一种解决方案是animated:NO
在animated:YES
整个代码中进行更改.这样,导航栏的显示和隐藏将作为动画的一部分进行排序.因此,当手势被取消并且动画向后运行到开始时,导航的显示/隐藏也会向后运行到开始 - 这两件事现在保持协调.
但是,如果你真的不想做出改变呢?那么,另一个解决方案是改变viewWillAppear:
为viewDidAppear:
整个.正如我已经说过的那样,viewWillAppear:
在动画开始时调用,即使手势无法完成,这也会导致事情失控.但viewDidAppear:
只有在手势完成(未取消)和动画已经结束时才会调用.
我更喜欢这两种解决方案中的哪一种?他们都不是!他们都强迫你做出你不想做出的改变.在我看来,真正的解决方案是使用转换协调器.
转换协调器是系统为此目的而提供的对象,即检测我们是否参与交互式转换并根据其是否被取消而表现不同.
专注于OneViewController的实现viewWillAppear:
.这是事情变得混乱的地方.当您在TwoViewController中并从左侧开始平移手势时,将viewWillAppear:
调用OneViewController .但是你取消了,放弃了手势而没有完成它.在这种情况下,您不希望在OneViewController中执行您正在执行的操作viewWillAppear:
.这正是转型协调员允许您做的事情.
那么,这是OneViewController的重写viewWillAppear:
.这可以解决问题,而无需进行任何其他更改:
-(void)viewWillAppear:(BOOL)animated{
[super viewWillAppear:animated];
id<UIViewControllerTransitionCoordinator> tc = self.transitionCoordinator;
if (tc && [tc initiallyInteractive]) {
[tc notifyWhenInteractionEndsUsingBlock:
^(id<UIViewControllerTransitionCoordinatorContext> context) {
if ([context isCancelled]) {
// do nothing!
} else { // not cancelled, do it
[self.navigationController setNavigationBarHidden:YES animated:NO];
}
}];
} else { // not interactive, do it
[self.navigationController setNavigationBarHidden:YES animated:NO];
}
}
Run Code Online (Sandbox Code Playgroud)
修复很简单,但我现在没有任何解释为什么会发生这种情况.
一个你的OneViewController改变你viewWillAppear
的,
-(void)viewWillAppear:(BOOL)animated{
// [self.navigationController setNavigationBarHidden:YES animated:NO];
self.navigationController.navigationBar.hidden = YES;
}
Run Code Online (Sandbox Code Playgroud)
并在第二和第三视图控制器上将其更改为,
-(void)viewWillAppear:(BOOL)animated{
//[self.navigationController setNavigationBarHidden:NO animated:NO];
self.navigationController.navigationBar.hidden = NO;
}
Run Code Online (Sandbox Code Playgroud)
奇怪但这将解决我们直接使用UINavigationBar的隐藏属性时的问题.
归档时间: |
|
查看次数: |
7133 次 |
最近记录: |