在引入了導(dǎo)航控制器UINavigationController和分欄控制器UITabBarController之后展懈,我們?cè)谠O(shè)置控件的frame的時(shí)候就需要注意避開(kāi)導(dǎo)航欄UINavigationBar 44+電源欄UIStatusBar 20的高度存崖,和底部分欄UITabBar 44的高度。底部分欄并沒(méi)有太多需要處理的冗栗,我們只需要在計(jì)算高度的時(shí)候避開(kāi)這44就可以了供搀。而導(dǎo)航欄因?yàn)榘该?半透明葛虐、第一個(gè)控件是否是UIScrollView或其子類(lèi)等造成frame.origin.y的起點(diǎn)不同。我們現(xiàn)在來(lái)分析一下。
1.edgesForExtendedLayout:UIRectEdge 擴(kuò)展布局的邊緣
在iOS7以后 UIViewController 開(kāi)始使用全屏布局掰盘,而且是默認(rèn)的屬性愧捕。通常涉及到布局,就離不開(kāi)這個(gè)屬性 edgesForExtendedLayout瘪阁,它是一個(gè)類(lèi)型為UIExtendedEdge的屬性管跺,指定UIViewController上的根視圖self.view邊緣要延伸的方向禾进。由于iOS7鼓勵(lì)全屏布局,所以它的默認(rèn)值是UIRectEdgeAll艇拍,四周邊緣均延伸宠纯,就是說(shuō)婆瓜,如果即使視圖中上有UINavigationBar,下有UITabBar碍讨,那么視圖仍會(huì)延伸覆蓋到四周的區(qū)域。
(1)UIRectEdgeAll(Defalut)
這里放置了一個(gè)frame為(0, 0, 100, 100)的view宵统,backgroundColor設(shè)置為redColor马澈,就是這個(gè)樣子弄息。也就是說(shuō)摹量,此時(shí)的self.view是從屏幕頂?shù)狡聊坏椎摹4藭r(shí)我們計(jì)算控件frame的y的時(shí)候凝果,如果想把控件在導(dǎo)航欄底部開(kāi)始睦尽,那么y就是64当凡。
(2)UIRectEdgeNone
因此,我們?yōu)榱瞬蛔屛覀兊目丶IView延伸到UINavigationBar下面浪慌,我們可以將該屬性設(shè)置為UIRectEdgeNone朴则。代碼如下:
[self setEdgesForExtendedLayout:UIRectEdgeNone];
ps:鑒于之前代碼OC與Swift都有佛掖,可能帶來(lái)的閱讀不習(xí)慣,以后貼代碼盡量使用OC欧宜,Swift獨(dú)有的那就沒(méi)辦法了拴魄。
很清晰的可以看出來(lái)在設(shè)置為UIRectEdgeNone之后,self.view的是從導(dǎo)航欄底部到底部分欄頂部的豪诲。此時(shí)我們計(jì)算控件frame的y的時(shí)候挂绰,如果想把控件在導(dǎo)航欄底部開(kāi)始葵蒂,那么y就是0。
(3)UIRectEdge
typedef NS_OPTIONS(NSUInteger, UIRectEdge) {
2
3 UIRectEdgeNone = 0,
4
5 UIRectEdgeTop = 1 << 0,
6
7 UIRectEdgeLeft = 1 << 1,
8
9 UIRectEdgeBottom = 1 << 2,
10
11 UIRectEdgeRight = 1 << 3,
12
13 UIRectEdgeAll = UIRectEdgeTop | UIRectEdgeLeft | UIRectEdgeBottom | UIRectEdgeRight
14
15 } NS_ENUM_AVAILABLE_IOS(7_0);
很明顯秦士,UIRectEdge是個(gè)枚舉類(lèi)型隧土。我們已經(jīng)分析完了UIRectEdgeNone和UIRectEdgeAll命爬,那么對(duì)UIRectEdgeTop和UIRectEdgeBottom也應(yīng)該有所了解了遇骑。UIRectEdgeLeft/UIRectEdgeRight也不難猜測(cè)揖曾,就是對(duì)左右的擴(kuò)展炭剪。目前沒(méi)有遇到過(guò)左右兩邊系統(tǒng)控件可能覆蓋掉自定義控件的情況,但遇到了我想大家也應(yīng)該心里有數(shù)了吧媒鼓。
2.translucent:Bool 半透明的
這個(gè)是self.navigationController.navigationBar的屬性错妖,設(shè)置導(dǎo)航條UINavigationBar是否半透明暂氯。默認(rèn)是YES,也就是半透明擎厢,看起來(lái)比較高大上动遭,與圖1效果相同。
當(dāng)設(shè)置為不透明NO的時(shí)候偷仿,就涉及到下面第三條屬性了绵估,不過(guò)在第三條默認(rèn)的情況下国裳,則被下壓,與圖2效果相同亿遂。
[self.navigationController.navigationBar setTranslucent:NO];
圖中空出的部分蛇数,即為導(dǎo)航條UINavigationBar是越。此時(shí)計(jì)算frame應(yīng)從導(dǎo)航欄下部為0開(kāi)始計(jì)算倚评,或者說(shuō)控件會(huì)被下壓64。
不過(guò)我們一般不會(huì)使用到這一條盔性,因?yàn)榘胪该餍Ч容^好看啊~
3.extendedLayoutIncludesOpaqueBars:Bool 不透明的條下是否可以擴(kuò)展
很明顯呢岗,這條需要與上一條translucent搭配使用的后豫,默認(rèn)為NO挫酿,也就是不可以擴(kuò)展。當(dāng)translucent設(shè)置為NO鸵赖,即導(dǎo)航欄UINavigationBar不透明的時(shí)候,默認(rèn)不能擴(kuò)展饵骨。若我們?cè)O(shè)置為YES茫打,則會(huì)出現(xiàn)這種情況:
我并沒(méi)有改變紅色view的frame老赤,而是被不透明的導(dǎo)航條蓋住看不到了。很明顯此時(shí)計(jì)算frame又是從屏幕最上方作為0開(kāi)始計(jì)算了弊予。
為了計(jì)算究竟是在電源條下方還是屏幕最上方作為y的0點(diǎn)开财,改變了紅色view的height為64和65重復(fù)試驗(yàn)责鳍,結(jié)果如下
結(jié)論是從屏幕上方作為y的0開(kāi)始計(jì)算历葛。
不過(guò)第2條都很少用,第3條使用的幾率...
4.automaticallyAdjustsScrollViewInsets:Bool 自動(dòng)校準(zhǔn)滾動(dòng)視圖的嵌入視圖
這個(gè)其實(shí)就很簡(jiǎn)單了乓诽,也是我們最常使用的一個(gè)吧宏娄。automaticallyAdjustsScrollViewInsets是一個(gè)bool類(lèi)型孵坚,默認(rèn)為YES窥淆,也就是會(huì)自動(dòng)校準(zhǔn)滾動(dòng)視圖的嵌入視圖忧饭。不過(guò)這個(gè)只針對(duì)于UIScrollView及其子視圖词裤,所以我們是用UITextView做一下測(cè)試鳖宾。
創(chuàng)建了一個(gè)frame為(0, 0, [UIScreen mainScreen].bounds.size.width, [UIScreen mainScreen].bounds.size.height)占據(jù)整個(gè)屏幕的UITextView鼎文,并放置了足夠多的文字因俐。在默認(rèn)automaticallyAdjustsScrollViewInsets為YES的前提下拇惋,我們測(cè)試下可能出現(xiàn)的結(jié)果。
似乎什么毛病都沒(méi)有啊很正常啊抹剩。但是不要忘記我設(shè)置的frame的y是0啊撑帖。那大家可能就好奇了,難道UIScrollView的滾動(dòng)視圖的frame是從導(dǎo)航欄下邊界算起的澳眷?不忙胡嘿,我們?cè)O(shè)置automaticallyAdjustsScrollViewInsets為NO再試試。
[self setAutomaticallyAdjustsScrollViewInsets:NO];
這個(gè)是一啟動(dòng)就出現(xiàn)的界面钳踊,我并沒(méi)有向上滑動(dòng)它的內(nèi)容區(qū)域灶平,也就是說(shuō)箍土,似乎此時(shí)的frame又是從屏幕下方開(kāi)始的了逢享。
不要慌,我們改一下設(shè)置試試看吴藻。
我將UITextView的frame設(shè)置為(0, 64, [UIScreen mainScreen].bounds.size.width, [UIScreen mainScreen].bounds.size.height)瞒爬,也就是y改成了64;然后改變了它的背景顏色為紅色redColor沟堡;最后將[self setAutomaticallyAdjustsScrollViewInsets:NO];這行代碼注掉侧但,讓它默認(rèn)為YES。
看一下效果航罗。
注意:導(dǎo)航欄是半透明的禀横,所以不存在被壓到紅色看不到的問(wèn)題,也就是說(shuō)粥血,UITextView的frame的y的64的位置柏锄,是導(dǎo)航欄下方;那么0自然就是在屏幕下方開(kāi)始計(jì)算了复亏。
很明顯趾娃,automaticallyAdjustsScrollViewInsets改變的并不是UIScrollView的frame,而是它的內(nèi)容區(qū)域contentView的可滾動(dòng)區(qū)域缔御,也就是scrollIndicatorInsets抬闷。這是我們能滾到的最大范圍。相當(dāng)于scrollIndicatorInsets這個(gè)屬性UIEdgeInsetsMake(<#CGFloat top#>, <#CGFloat left#>, <#CGFloat bottom#>, <#CGFloat right#>)的值從UIEdgeInsetsMake(0, 0, 0, 0)變?yōu)榱薝IEdgeInsetsMake(64, 0, 0, 0)耕突。這就是automaticallyAdjustsScrollViewInsets這個(gè)屬性的作用笤成。
另外再說(shuō)一點(diǎn)评架,這個(gè)automaticallyAdjustsScrollViewInsets的屬性,只對(duì)加在self.view上的第一個(gè)子視圖起作用炕泳,所以我們可以在將UIScrollView加載到self.view上之前先加載一個(gè)其他控件古程,這樣也能達(dá)到同樣的效果。
ps:
當(dāng)升級(jí)到iOS 11的時(shí)候,發(fā)現(xiàn)UIScrollView 有莫名其妙的偏移了 可是明明設(shè)置了
automaticallyAdjustsScrollViewInsets
這是因?yàn)閕OS 11為UIScrollView 添加了新的屬性contentInsetAdjustmentBehavior 這是一個(gè)枚舉
找到UIScrollViewContentInsetAdjustmentNever 從來(lái)不自動(dòng)調(diào)整和automaticallyAdjustsScrollViewInsets = NO 是一個(gè)功效 這樣就解決了iOS 11這個(gè)bug
if (@available(iOS 11.0, *)) {
Scrollview.contentInsetAdjustmentBehavior = UIScrollViewContentInsetAdjustmentNever;
} else {
// Fallback on earlier versions
}