最近在做一個模仿iOS11 Music的項目,其中一個播放器頁面是這個樣子的。
沒錯,他的頂部露出了一塊前一個頁面一部分。
我們都知道,默認的present方式展現的新頁面,是看不到上一個頁面的內容的,即便是將controller的view透明,也只能看到黑色的背景。蘋果應該是出于降低內存的考慮,當一個新的頁面被present或push出來后,就將之前的頁面移除了。
要實現這個功能,我首先想到的是把上一個頁面截圖,然后放在present出來的頁面的底下。。。腦洞也是夠大的。其實蘋果早就為我們準備了一個屬性:modalPresentationStyle,使用他,就能控制是否隱藏前一個頁面。(接下來我們統一把前一個頁面稱為presenting VC, 把后一個頁面稱為presented VC)
modalPresentationStyle這個屬性的可選值非常多:
fullScreen:(默認)代表彈出VC時,presented VC充滿全屏,如果彈出VC的wantsFullScreenLayout設置為YES的,則會填充到狀態欄下邊,否則不會填充到狀態欄之下。
pageSheet:代表彈出是彈出VC時,presented VC的高度和當前屏幕高度相同,寬度和豎屏模式下屏幕寬度相同,剩余未覆蓋區域將會變暗并阻止用戶點擊,這種彈出模式下,豎屏時UIModalPresentationFullScreen的效果一樣,橫屏時候兩邊則會留下變暗的區。
就算自己把這個圖做出來了,還是想不明白具體是什么樣子的,好在設置Wi-Fi里被我揪出了一列
系統設置的Wi-Fi密碼界面,豎屏是全屏展示,橫屏的話就會變成一個正方形,這個大小應該是系統控制的。類似的頁面應該ipad上會更多。
formSheet:這種模式下,presented VC的高度和寬度均會小于屏幕尺寸,presented VC居中顯示,四周留下變暗區域。如果設備處于橫向并且鍵盤可見,則視圖的位置向上調整,以使視圖保持可見。(是不是很熟悉,我們的alert就是這種方式呈現的)
currentContext:這種模式下,presented VC的彈出方式和presenting VC的父VC的方式相同。
custom:自定義模式。這個模式可以最大化自定義專場的方式,需要實現UIViewControllerTransitioningDelegate代理。
overFullScreen:(新)簡單說就是不隱藏presenting VC,用于presented VC的view有透明的情況使用。那么這個和之前的有什么區別呢,區別主要在亮點:1.背景不會變深色(但還是會屏蔽觸控)2.presented VC view的大小和presenting VC一樣大時(即完全遮擋),前面幾個選項會直接隱藏presenting VC,而overFullScreen不考慮遮擋問題,無條件顯示presenting VC。這就對presented VC大小和presenting VC一樣大但有透明的情況適用。
overCurrentContext:(新)這個模式也能達到overFullScreen的效果,不同的是它會把跟控制器(tabbar)覆蓋到presented VC上面(讀了API還是搞不清是啥意思。。。)
popover:一種類似于Mac上全局字典的彈出方式,帶有一個箭頭,在iphone上顯示的是全屏效果,只有在大屏幕上才顯示popover效果。
好了,研究了這么多,我們到底應該選擇哪一個呢。起初我認為formSheet比較合適,因為他默認實現了背景變暗的效果(Music里也有這個效果)。但使用之后發現始終無法完成這個效果,要么presented VC的大小改變不了(storyboard),要么presenting VC是黑色。后來我想了一下,這個formSheet起初設計的場景,就是alert這種彈出框的效果,所以它默認是居中的。如果要使用formSheet,還要控制view的位置,不太合理。而且storyboard中vc的view是無法改變大小的,因此只能使用overFullScreen模式,將presented VC的透明度設為0,然后再鋪一個View上去。
最后使用的時候有幾個注意點。首先在早期modalPresentationStyle的屬性是賦給presenting VC的,但后來都統一賦給presented VC,這個邏輯也很正確,這種需求往往是跟著presented VC走的。
其次是,modalPresentationStyle賦值的時機很重要,要在present事件之前賦值。因此不要在viewDidLoad里面修改modalPresentationStyle,而在初始化方法里修改。storyboard則要在required init?(coder aDecoder: NSCoder)中修改。