iOS 7: 隱藏的特性和解決之道
當(dāng) iOS7 剛發(fā)布的時(shí)候,全世界的蘋果開發(fā)人員都立馬嘗試著去編譯他們的app,接著再花上數(shù)月的時(shí)間來修復(fù)任何出現(xiàn)的故障,甚至重做app。這樣的結(jié)果,使得人們根本無暇去探究 iOS7 所帶來的新東西。一些明顯而細(xì)微的更新,比如說[NSArray firstObject],這個(gè)方法可追溯到 iOS4 時(shí)代,現(xiàn)在被提為公有API,除此之外,還有很多隱藏的特性等著我們?nèi)ネ诰颉?/p>本文引用地址:http://butianyuan.cn/article/201609/304760.htm
平滑淡入淡出動(dòng)畫
我這里要討論的并非新的彈性動(dòng)畫APIs 或者 UIDynamics,而是一些更細(xì)微的東西。CALayer增加了兩個(gè)新方法:allowsGroupOpacity和allowsEdgeAntialiasing?,F(xiàn)在,組不透明度(group opacity)不再是什么新鮮的東西了。iOS會(huì)多次使用存在于 Info.plist 中的鍵UIViewGroupOpacity并可在應(yīng)用程序范圍內(nèi)啟用或禁用它。對(duì)于大多數(shù)apps而言,這(譯注:啟用)并非所期望的,因?yàn)樗鼤?huì)降低整體性能。在 iOS7 中,用 SDK7 所鏈接的程序,這項(xiàng)屬性默認(rèn)是啟用的。當(dāng)它被啟用時(shí),一些動(dòng)畫將會(huì)變得不流暢,它也可以在layer層上被控制。
一個(gè)有趣的細(xì)節(jié),如果allowsGroupOpacity啟用的話,_UIBackdropView(在UIToolbar或者UIPopoverView中的背景視圖)不能對(duì)其模糊進(jìn)行動(dòng)畫處理,所以當(dāng)你做一個(gè)alpha轉(zhuǎn)換時(shí),你可能會(huì)臨時(shí)禁用這項(xiàng)屬性。因?yàn)檫@會(huì)降低動(dòng)畫體驗(yàn),你可以回退到舊的方式然后在動(dòng)畫期間臨時(shí)啟用shouldRasterize。別忘了設(shè)置適當(dāng)?shù)膔asterizationScale,否則在retina的設(shè)備上這些視圖會(huì)成鋸齒狀。
如果你想要復(fù)制的 Safari 顯示所有選項(xiàng)卡時(shí)的動(dòng)畫,那么邊緣抗鋸齒屬性將變得非常有用。
阻塞動(dòng)畫
一個(gè)小但非常有用的新方法[UIView performWithoutAnimation:]。它是一個(gè)簡單的封裝,先檢查動(dòng)畫當(dāng)前是否啟用,然后禁止動(dòng)畫,執(zhí)行塊語句,最后重新啟用動(dòng)畫。一個(gè)需要說明的地方是,它并不會(huì)阻塞基于 CoreAnimation 的動(dòng)畫。因此,不用急于將你的方法調(diào)用從:
[CATransaction begin];
[CATransaction setDisableActions:YES];
view.frame = CGRectMake(...);
[CATransaction commit];
替換為:
1
2
3[UIView performWithoutAnimation:^{
view.frame = CGRectMake(...);
}];
但是,絕大多數(shù)情況下這樣也能工作的很好,只要你不直接處理CALayers。
iOS7 中,我有很多代碼路徑(主要是 UITableViewCells)需要額外的保護(hù),防止意外的動(dòng)畫,例如,如果一個(gè)彈窗的大小調(diào)整了,那么同時(shí)顯示中的表視圖將因?yàn)楦叨鹊淖兓虞d新的cell。我通常的做法是將整個(gè) layoutSubviews 的代碼包扎到一個(gè)動(dòng)畫塊中:
(void)layoutSubviews
{
// Otherwise the popover animation could leak into our cells on iOS 7 legacy mode.
[UIView performWithoutAnimation:^{
[super layoutSubviews];
_renderView.frame = self.bounds;
}];
}
處理長表視圖
UITableView 非??焖俑咝?,除非你開始使用tableView:heightForRowAtIndexPath:,它會(huì)開始為你表中任意元素調(diào)用此方法,即便沒有可視對(duì)象,就比如其內(nèi)在的UIScrollView只是去獲取正確的contentSize。此前有一些變通方法,但都不好用。iOS7 中,蘋果公司終于承認(rèn)這一問題,并添加tableView:estimatedHeightForRowAtIndexPath:,這個(gè)方法延遲了實(shí)際滾動(dòng)時(shí)間成本的大部分。如果你不知道一個(gè)cell的大小,返回UITableViewAutomaticDimension即可。
對(duì)于節(jié)頭/尾(section headers/footers),現(xiàn)在也有類似的API了。
UISearchDisplayController
蘋果的 search controller 使用了新的技巧來簡化移動(dòng) search bar 到 navigation bar 的過程。啟用 displaysSearchBarInNavigationBar 就可以了(除非你還要用到 scope bar,我只能說你真不幸)。我倒是很喜歡這么做,但比較遺憾的是,iOS7 上的 UISearchDisplayController 貌似被摧殘的比較嚴(yán)重,尤其是iPad。蘋果公司看上去像是沒時(shí)間處理這個(gè)問題的樣子(原文:Apple seems to have run out of time),對(duì)于顯示的搜索結(jié)果并不會(huì)隱藏實(shí)際的表視圖。在 iOS7 之前,這并沒有問題,但是現(xiàn)在 searchResultsTableView 有一個(gè)透明的背景色,使它看上去相當(dāng)糟糕。作為一種變通方法,你可以設(shè)置不透明色或者取道于富于技巧的手段來獲得你所期望的。關(guān)于這個(gè)控件會(huì)出現(xiàn)各種各樣的結(jié)果,當(dāng)使用displaysSearchBarInNavigationBar時(shí)甚至不會(huì)展示搜索表視圖。
你的結(jié)果可能有所不同,但我是使用了一些手段來讓displaysSearchBarInNavigationBar工作的:
(void)restoreOriginalTableView
{
if (PSPDFIsUIKitFlatMode() self.originalTableView) {
self.view = self.originalTableView;
}
}
- (UITableView *)tableView
{
return self.originalTableView ?: [super tableView];
}
- (void)searchDisplayController:(UISearchDisplayController *)controller
didShowSearchResultsTableView:(UITableView *)tableView
{
// HACK: iOS 7 requires a cruel workaround to show the search table view.
if (PSPDFIsUIKitFlatMode()) {
if (!self.originalTableView) self.originalTableView = self.tableView;
self.view = controller.searchResultsTableView;
controller.searchResultsTableView.contentInset = UIEdgeInsetsZero; // Remove 64 pixel gap
}
}
- (void)searchDisplayController:(UISearchDisplayController *)controller
didHideSearchResultsTableView:(UITableView *)tableView
{
[self restoreOriginalTableView];
}
這里,別忘了在viewWillDisappear中調(diào)用restoreOriginalTableView,否則會(huì)發(fā)送crash。
記住這是唯一的解決辦法;可能有不少激進(jìn)的方法不替換視圖本身,但這個(gè)問題確實(shí)應(yīng)該由蘋果公司來修復(fù)。(TODO: RADAR!)
評(píng)論