iOS开发中一些"有挑战"的问题

本文源自这里, 另外还有姊妹篇iOS开发中一些"有趣"的问题

目录

  • 问题1: navigation push时隐藏的Tarbar怎么又回来了

  • 问题2: 莫名消失的MBProgressHUD

  • 问题3: 奇怪的DAContextMenuTableViewController只在iOS7工作不正常

问题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上侧滑后, 出现选项按钮的效果

iOS开发中一些
ios_difficulty_problems_01.png

这里使用了第三方库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;
    }
}

更多文章, 请支持我的个人博客

你可能感兴趣的:(iOS开发中一些"有挑战"的问题)