本文源自这里, 另外还有姊妹篇iOS开发中一些"有趣"的问题
目录
问题1: navigation push时隐藏的Tarbar怎么又回来了
问题描述
模拟类似Present的效果, 实现的思路如下
通过自定义Presented ViewController进入动画, 然后切换window的rootViewController到Presented ViewController
但是这种方式(先不谈论这种方式的方式是否合理和规范)会导致已隐藏的tabbar又显示出来的问题
问题发生在这样的条件下
原先的rootViewController是一个UITabBarController
每个Tab的子ViewController是NavigationController
push一个ViewController到NavigationController, 并且"hidesBottomBarWhenPushed = YES"
切换rootViewController到Presented ViewController, 然后再切换回之前的UITabBarController
问题分析
在rootViewController是UITabBarController的情况下, push ViewController到NavigationController时, 配置"hidesBottomBarWhenPushed = YES"用来隐藏Tabbar
但是此时隐藏Tabbar的配置并不是存储在push的ViewController里, 而是与push动作相关联(这段是我的推测, 并没有源码做论证)
所以将rootViewController切换回之前的UITabBarController后, Tabbar就又显示出来了
问题解决
其实这个问题与刚开始的实现思路有关系, 这种模拟Present效果的方式并不常见, 所以必要性有待商榷, 但是这样也算是暴露出了一个iOS UI开发的问题
解决的思路是延续Apple的方式, 即push一个空的ViewController, 再pop出来, 这样Tabbar就与push动作又发生了关联, 由此Tabbar就又被隐藏了起来
UIViewController *dumbViewController = [[UIViewController alloc] init];
[navigationController pushViewController:dumbViewController animated:NO];
[navigationController popViewControllerAnimated:NO];
问题2: 莫名消失的MBProgressHUD
问题描述
在点击Actionsheet的选项后, 弹出一个覆盖全屏的spinner(spinner使用的是第三库MBProgressHUD, 添加到keyWindow上), 同时ActionSheet也自动隐藏起来(因为点击选项了)
但是spinner弹出之后, 又立马迅速地消失了, 而如果再次弹出Actionsheet时, spinner又会随着Actionsheet一起显示出来
问题分析
从现象来看, 其实spinner并没有销毁, 而只是隐藏了起来, 否则不会随着Actionsheet第二次弹出而弹出
问题代码的实现是这样的
- (void)actionSheet:(UIActionSheet *)actionSheet clickedButtonAtIndex:(NSInteger)buttonIndex {
// show wait spinner, add it to keywindow
}
加载spinner到keywindow是在Actionsheet的clickedButtonAtIndex delegate里, 所以事件的时序是这样的
加载spinner到keywindow -> 隐藏Actionsheet
由于Actionsheet也是加载到底层的window上, 所以先前显示的spinner可能会随着Actionsheet的隐藏而隐藏起来了
问题解决
为了避免Actionsheet隐藏时带来的干扰, 我们希望事件的时序是这样的
隐藏Actionsheet -> 加载spinner到keywindow
很简单, 只需要用新的Actionsheet的delegate方法didDismissWithButtonIndex来替代clickedButtonAtIndex
- (void)actionSheet:(UIActionSheet *)actionSheet didDismissWithButtonIndex:(NSInteger)buttonIndex {
// show wait spinner, add it to keywindow
}
问题3: 奇怪的DAContextMenuTableViewController只在iOS7工作不正常
问题描述
要实现在cell上侧滑后, 出现选项按钮的效果
这里使用了第三方库DAContextMenuTableViewController
但是在使用shouldDisableUserInteractionWhileEditing选
项后, 侧滑cell后不能响应事件
并且此问题只出现在iOS7版本中, 而iOS8+系统并不存在该问题
问题分析
这里牵涉到HitTest的问题, 原理和概念参考这里
不能响应事件, 说明事件被拦截了, 即在要响应事件的view上层有其他view, 而这个其他view拦截了事件
通过打印UITableView的subViews, 发现确实存在这样的中间view
UITableView(1级)
----UITableViewWrapperView(2级)
--------UITableViewCell(3级)
--------UITableViewCell(3级)
----UIView(2级)
----UIImageView(2级)
UITableView是肯定能响应事件的, 而UITableViewCell并没有接收到事件, 那很可能是UITableViewWrapperView将事件拦截了
查看DAContextMenuTableViewController源码发现这里确实有问题
for (UIView *view in self.tableView.subviews) {
if ((view.gestureRecognizers.count == 0) && view != self.cellDisplayingMenuOptions && view != self.overlayView) {
view.userInteractionEnabled = NO;
}
}
打印发现在iOS7系统中UITableViewWrapperView的view.gestureRecognizers.count=0
而在iOS8+系统中UITableViewWrapperView的view.gestureRecognizers.count>0
所以在iOS7中UITableViewWrapperView的userInteractionEnabled=NO, 所以事件就被UITableViewWrapperView拦截了而没有传递到cell
究其原因, 是不同iOS版本的内部实现差异导致的, 同时, 这种依赖于Apple平台的第三方库也要需要随着iOS的更新而更新
问题解决
条件语句不使用view.gestureRecognizers.count, 而是通过其subViews类型来判断当前view是否是UITableViewWrapperView
for (UIView *view in self.imTable.subviews) {
if (!(view.subviews.count > 0 && [[view.subviews firstObject] isKindOfClass:[UITableViewCell class]])) {
view.userInteractionEnabled = NO;
}
}
更多文章, 请支持我的个人博客