本文源自這里, 另外還有姊妹篇iOS開發(fā)中一些"有趣"的問題
目錄
問題1: navigation push時隱藏的Tarbar怎么又回來了
問題描述
模擬類似Present的效果, 實(shí)現(xiàn)的思路如下
通過自定義Presented ViewController進(jìn)入動畫, 然后切換window的rootViewController到Presented ViewController
但是這種方式(先不談?wù)撨@種方式的方式是否合理和規(guī)范)會導(dǎo)致已隱藏的tabbar又顯示出來的問題
問題發(fā)生在這樣的條件下
原先的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動作相關(guān)聯(lián)(這段是我的推測, 并沒有源碼做論證)
所以將rootViewController切換回之前的UITabBarController后, Tabbar就又顯示出來了
問題解決
其實(shí)這個問題與剛開始的實(shí)現(xiàn)思路有關(guān)系, 這種模擬Present效果的方式并不常見, 所以必要性有待商榷, 但是這樣也算是暴露出了一個iOS UI開發(fā)的問題
解決的思路是延續(xù)Apple的方式, 即push一個空的ViewController, 再pop出來, 這樣Tabbar就與push動作又發(fā)生了關(guān)聯(lián), 由此Tabbar就又被隱藏了起來
UIViewController *dumbViewController = [[UIViewController alloc] init];
[navigationController pushViewController:dumbViewController animated:NO];
[navigationController popViewControllerAnimated:NO];
問題2: 莫名消失的MBProgressHUD
問題描述
在點(diǎn)擊Actionsheet的選項后, 彈出一個覆蓋全屏的spinner(spinner使用的是第三庫MBProgressHUD, 添加到keyWindow上), 同時ActionSheet也自動隱藏起來(因?yàn)辄c(diǎn)擊選項了)
但是spinner彈出之后, 又立馬迅速地消失了, 而如果再次彈出Actionsheet時, spinner又會隨著Actionsheet一起顯示出來
問題分析
從現(xiàn)象來看, 其實(shí)spinner并沒有銷毀, 而只是隱藏了起來, 否則不會隨著Actionsheet第二次彈出而彈出
問題代碼的實(shí)現(xiàn)是這樣的
- (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工作不正常
問題描述
要實(shí)現(xiàn)在cell上側(cè)滑后, 出現(xiàn)選項按鈕的效果

這里使用了第三方庫DAContextMenuTableViewController
但是在使用shouldDisableUserInteractionWhileEditing選
項后, 側(cè)滑cell后不能響應(yīng)事件
并且此問題只出現(xiàn)在iOS7版本中, 而iOS8+系統(tǒng)并不存在該問題
問題分析
這里牽涉到HitTest的問題, 原理和概念參考這里
不能響應(yīng)事件, 說明事件被攔截了, 即在要響應(yīng)事件的view上層有其他view, 而這個其他view攔截了事件
通過打印UITableView的subViews, 發(fā)現(xiàn)確實(shí)存在這樣的中間view
UITableView(1級)
----UITableViewWrapperView(2級)
--------UITableViewCell(3級)
--------UITableViewCell(3級)
----UIView(2級)
----UIImageView(2級)
UITableView是肯定能響應(yīng)事件的, 而UITableViewCell并沒有接收到事件, 那很可能是UITableViewWrapperView將事件攔截了
查看DAContextMenuTableViewController源碼發(fā)現(xiàn)這里確實(shí)有問題
for (UIView *view in self.tableView.subviews) {
if ((view.gestureRecognizers.count == 0) && view != self.cellDisplayingMenuOptions && view != self.overlayView) {
view.userInteractionEnabled = NO;
}
}
打印發(fā)現(xiàn)在iOS7系統(tǒng)中UITableViewWrapperView的view.gestureRecognizers.count=0
而在iOS8+系統(tǒng)中UITableViewWrapperView的view.gestureRecognizers.count>0
所以在iOS7中UITableViewWrapperView的userInteractionEnabled=NO, 所以事件就被UITableViewWrapperView攔截了而沒有傳遞到cell
究其原因, 是不同iOS版本的內(nèi)部實(shí)現(xiàn)差異導(dǎo)致的, 同時, 這種依賴于Apple平臺的第三方庫也要需要隨著iOS的更新而更新
問題解決
條件語句不使用view.gestureRecognizers.count, 而是通過其subViews類型來判斷當(dāng)前view是否是UITableViewWrapperView
for (UIView *view in self.imTable.subviews) {
if (!(view.subviews.count > 0 && [[view.subviews firstObject] isKindOfClass:[UITableViewCell class]])) {
view.userInteractionEnabled = NO;
}
}
更多文章, 請支持我的個人博客