因為使用簡單,autoresizing的自動布局方式一直挺受我偏愛的舀患。然而前端時間測試的時候徽级,出現(xiàn)了幾個布局上的bug,調(diào)試后發(fā)現(xiàn)原來是沒有用正確姿勢使用autoresizing所致的(╥﹏╥)聊浅。
為了描述一下這個bug餐抢,假裝我寫了這樣一段代碼:
CGRect parentFrame = CGRectMake(0, 0, 100, 100);
UIView *parent = [[UIView alloc] initWithFrame:parentFrame];
parent.backgroundColor = [UIColor redColor];
[self.view addSubview:parent];
UIView *son = [[UIView alloc] initWithFrame:CGRectMake(0, 50, 100, 50)];
son.backgroundColor = [UIColor blueColor];
son.autoresizingMask = UIViewAutoresizingFlexibleHeight;
[parent addSubview:son];
[parent setFrame:CGRectMake(0, 0, 100, 0)];
[parent setFrame:parentFrame];
大意是,希望son
這個視圖的底部永遠和parent
視圖的底部對齊低匙,而son
視圖的頂部永遠和parent
視圖的頂部有50
單位的距離旷痕。也就是這樣的結(jié)果:
但是運行完這段代碼后我得到的結(jié)果是這樣的:
于是bug就產(chǎn)生了(╥﹏╥)
為什么會這樣呢?明明正確設(shè)置了autoresizing參數(shù)顽冶,可最后得到了錯誤的布局結(jié)果欺抗。仔細一想,原來是因為其中經(jīng)歷了
[parent setFrame:CGRectZero];
這個步驟强重。
在我的理解中佩迟,如果僅有UIViewAutoresizingFlexibleHeight
,則表示竿屹,無論parent
視圖的尺寸如何變化报强,son
視圖的上邊界和parent
視圖的上邊界的距離不變,son
視圖的下邊界和parent
視圖的下邊界的距離不變拱燃,寫成公式可能就是:
CGRectGetMinY(parent.bounds) - CGRectGetMinY(son.frame) 不變
CGRectGetMaxY(parent.bounds) - CGRectGetMaxY(son.frame) 不變
最開始秉溉,parent
視圖的bounds
為(0, 0, 100, 100)
,而son
視圖的frame
為(0, 50, 100, 50)
,也就是說:
CGRectGetMinY(parent.bounds) - CGRectGetMinY(son.frame) = -50
CGRectGetMaxY(parent.bounds) - CGRectGetMaxY(son.frame) = 0
后來召嘶,parent
視圖的bounds
變?yōu)?code>(0, 0, 0, 0)父晶,此時若輸出son
視圖的frame,會發(fā)現(xiàn)frame = (0 50; 0 0)
弄跌。也就是說這個時候
CGRectGetMinY(parent.bounds) - CGRectGetMinY(son.frame) = -50
CGRectGetMaxY(parent.bounds) - CGRectGetMaxY(son.frame) = -50
這個結(jié)果和我所理解的UIViewAutoresizingFlexibleHeight
矛盾了甲喝。
矛盾就出在,如果要嚴(yán)格按照“不變”的規(guī)則行事的話铛只,此時son.frame.size.height
應(yīng)該為-50
才對埠胖。
但是尺寸怎么可以是負值呢,可能autoresizing出于這個考慮淳玩,將-50
的高度處理成了0
直撤。這也就說明,在程序執(zhí)行到這一步的時候蜕着,失去了-50
這個信息谋竖。
最后,當(dāng)parent
視圖的bounds
回到(0, 0, 100, 100)
的時候承匣,autoresizing保持了
CGRectGetMinY(parent.bounds) - CGRectGetMinY(son.frame) = -50
CGRectGetMaxY(parent.bounds) - CGRectGetMaxY(son.frame) = -50
這個關(guān)系不變蓖乘,導(dǎo)致了son
視圖的高度最終變成了100
∪推看一眼代碼最終執(zhí)行的結(jié)果嘉抒,果然是這樣。
所以宽闲,我的bug就出在众眨,同事因為他的業(yè)務(wù)需要,改變了我負責(zé)的最外層視圖的frame容诬,而后又將其改回原值(他以為什么也不會發(fā)生娩梨,我開始也這么以為……),這個過程中览徒,我負責(zé)的子視圖在autoresize時出現(xiàn)了剛才的問題狈定,導(dǎo)致最后呈現(xiàn)出了錯誤的布局。
在解決這個問題的時候习蓬,我還想到了纽什,如果autoresizing不將負值的寬高轉(zhuǎn)換成0,會怎樣呢躲叼?
試了試芦缰,發(fā)現(xiàn)UIView
會自動將負值的寬高轉(zhuǎn)換成正值。
比如執(zhí)行完這幾行代碼后
UIView *view = [[UIView alloc] init];
CGRect rect = CGRectMake(100, 100, -50, -50);
view.frame = rect;
打印view
視圖枫慷,會發(fā)現(xiàn)
<UIView: 0x7ff88bd4db00; frame = (50 50; 50 50); layer = <CALayer: 0x7ff88bd4d330>>
view
視圖的frame
被轉(zhuǎn)換了让蕾。
所以不管怎么樣浪规,使用autoresizing時,如果不小心讓某個視圖的寬高變成了負值探孝,則一定會損失一部分信息笋婿,導(dǎo)致最后即便父視圖的frame
回到原值,子視圖的frame
也會出現(xiàn)問題顿颅。