CGGeometry 中提供了取特定 CGRect 值的便捷方法。
- CGRectGetMinX
- CGRectGetMinY
- CGRectGetMidX
- CGRectGetMidY
- CGRectGetMaxX
- CGRectGetMaxY
- CGRectGetWidth
- CGRectGetHeight
這其中CGRectGetMidX
,CGRectGetMidY
,CGRectGetMaxX
,CGRectGetMaxY
四個方法十分有用。用CGRectGetMaxX
代替frame.origin.x + frame.size.width
將使代碼更加清晰北戏、語義上也更為生動直觀。另外三個方法也同樣英遭,他們都可以用來代替類似這樣的代碼庵佣。
-
CGRectGetMidX
用來替代frame.origin.x + frame.size.width / 2
-
CGRectGetMidY
用來替代frame.origin.y + frame.size.height / 2
-
CGRectGetMaxX
用來替代frame.origin.x + frame.size.width
-
CGRectGetMaxY
用來替代frame.origin.y + frame.size.height
這時你也許會想到检柬,那CGRectGetMinX
,CGRectGetMinY
,CGRectGetWidth
,CGRectGetHeight
四個方法是不是也是用來代替類似這樣的代碼。
-
CGRectGetMinX
用來替代frame.origin.x
-
CGRectGetMinY
用來替代frame.origin.y
-
CGRectGetWidth
用來替代frame.size.width
-
CGRectGetHeight
用來替代frame.size.width
答案是肯定的茴恰。但這四個方法看起來卻不是那么有必要颠焦。因?yàn)楦苯诱{(diào)用相比,這樣寫代碼要更長往枣。
- CGRectGetMinX(frame)
- frame.origin.x
而且如果想要喚起 Xcode 的聯(lián)想伐庭,最少需要輸入“CGRectGet”八個字母。而直接調(diào)用通常只需要輸入“f”婉商,“.o”似忧,“.x”五個字母就能聯(lián)想完成渣叛。經(jīng)過性能測試丈秩,CGRectGetMinX(frame) 的億次調(diào)用耗時561毫秒,而直接調(diào)用由于不明原因淳衙,不管循環(huán)多少次測試調(diào)用時間都低于1毫秒蘑秽。竟然代碼更長,輸入更慢箫攀,效率更低肠牲,那 CGGeometry 提供這些接口的意義在哪呢。其實(shí)靴跛,僅憑代碼統(tǒng)一的代碼風(fēng)格缀雳,生動直觀的語義也值得你這樣去做。而且效率上的差異只是理論數(shù)值梢睛,實(shí)際上CGRectGet的10萬次調(diào)用只耗時1毫秒肥印,在整個APP的運(yùn)行期間也很難有超過10萬次的調(diào)用。
蘋果官方文檔推薦使用 CGGeometry 方法绝葡,同時盡量避免直接調(diào)用深碱。事實(shí)上僅僅因?yàn)樯鲜龅倪@些好處蘋果是不會建議盡量避免直接調(diào)用的,這兩種調(diào)用方法其實(shí)存在這本質(zhì)的差異藏畅。在平時的使用中我們沒有遇到差異敷硅,是因?yàn)槲覀兪褂玫?frame 或 bounds 通常都是正數(shù),當(dāng)負(fù)數(shù)出現(xiàn)的時候愉阎,有意思的事情就來了绞蹦。
StackOverflow摘自蘋果郵件列表的原文說明了這個現(xiàn)象。大意就是“CGRectGetWidth/Height 會將 width 或者 height 格式化榜旦,格式化基本上只是檢查 width 或者 height 是否為負(fù)數(shù)幽七,如果為負(fù)數(shù)則取絕對值”。下邊就來解釋這個現(xiàn)象背后的原因和他們本質(zhì)的差別章办。
CGRectGetWidth/Height will normalize the width or height before returning them. Normalization is basically just checking if the width or height is negative, and negating it to make it positive if so.
CGRect 是用來儲存矩形幾何信息的容器锉走,通過這些信息就能知道怎么去繪制矩形滨彻。UIView 通過 CGRect 類型的成員變量 frame 來描述自己的位置和形狀。通過 CGRectGet 方法獲取到的是 view 的實(shí)際位置和形狀挪蹭,而直接調(diào)用獲取的只是描述幾何體位置和形狀的信息亭饵,他們的是帶有方向性的。比如梁厉,view 的寬是-100辜羊,代表的是在 x 軸反方向的100,最終繪制出來矩形的寬還是100词顾,只是在 x 軸負(fù)方向而已八秃。所以,通過 CGRectGetWidth(frame) 獲取到的就是真實(shí)的寬度100,而直接調(diào)用只能獲取同時描述寬度和方向的數(shù)值-100肉盹。這看起來只是取絕對值這么簡單昔驱,但其他方法可并不是這樣。通過如下代碼繪制出來下圖所示的兩個 view 將幫助你更好的理解這一點(diǎn)上忍。
UIView *view = [[UIView alloc] initWithFrame:CGRectMake(200, 500, 100, 100)];
view.backgroundColor = [UIColor grayColor];
[self.view addSubview:view];
UIView *subview = [[UIView alloc] initWithFrame:CGRectZero];
subview.backgroundColor = [UIColor lightGrayColor];
[view addSubview:subview];
CGRect frame = CGRectMake(-50, -100, -100, -150);
NSLog(@"%f, %f", CGRectGetMinX(frame), frame.origin.x);
NSLog(@"%f, %f", CGRectGetMinY(frame), frame.origin.y);
NSLog(@"%f, %f", CGRectGetMidX(frame), frame.origin.x + frame.size.width / 2);
NSLog(@"%f, %f", CGRectGetMidY(frame), frame.origin.y + frame.size.height / 2);
NSLog(@"%f, %f", CGRectGetMaxX(frame), frame.origin.x + frame.size.width);
NSLog(@"%f, %f", CGRectGetMaxY(frame), frame.origin.y + frame.size.height);
NSLog(@"%f, %f", CGRectGetWidth(frame), frame.size.width);
NSLog(@"%f, %f", CGRectGetHeight(frame), frame.size.height);
subview.frame = frame;
通過圖片顯而易見骤肛,使用 CGRectGetMinX 獲取到的是 viewB 顯示在屏幕上最左邊位置,就是-150窍蓝。而通過 frame.origin.x 獲取到的必然是-50腋颠。簡單來說,只要 width 或者 height 是負(fù)數(shù)吓笙,那么這個 view 的左右或者上下其實(shí)是翻轉(zhuǎn)過的淑玫。你之前用直接調(diào)用的方法(frame.origin.x + frame.size.width)去獲取的(-50 - 100 = -150)其實(shí) view 左邊。
代碼打印出來 CGRectGet 方法的數(shù)據(jù)都符合這樣的規(guī)則面睛。
2016-02-26 15:40:13.141 LPTest[2319:859916] -150.000000, -50.000000
2016-02-26 15:40:13.141 LPTest[2319:859916] -250.000000, -100.000000
2016-02-26 15:40:13.141 LPTest[2319:859916] -100.000000, -100.000000
2016-02-26 15:40:13.141 LPTest[2319:859916] -175.000000, -175.000000
2016-02-26 15:40:13.141 LPTest[2319:859916] -50.000000, -150.000000
2016-02-26 15:40:13.141 LPTest[2319:859916] -100.000000, -250.000000
2016-02-26 15:40:13.142 LPTest[2319:859916] 100.000000, -100.000000
2016-02-26 15:40:13.142 LPTest[2319:859916] 150.000000, -150.00000
通過這樣的規(guī)則絮蒿,我們推理出這八種方法的函數(shù)原型。如下所示侮穿。
CG_EXTERN CGFloat CGRectGetMinX(CGRect rect) {
return rect.origin.x + (rect.size.width > 0? 0: rect.size.width);
}
CG_EXTERN CGFloat CGRectGetMinY(CGRect rect) {
return rect.origin.y + (rect.size.height > 0? 0: rect.size.height);
}
CG_EXTERN CGFloat CGRectGetMidX(CGRect rect) {
return rect.origin.x + rect.size.width / 2;
}
CG_EXTERN CGFloat CGRectGetMidY(CGRect rect) {
return rect.origin.y + rect.size.height / 2;
}
CG_EXTERN CGFloat CGRectGetMaxX(CGRect rect) {
return rect.origin.x + (rect.size.width < 0? 0: rect.size.width);
}
CG_EXTERN CGFloat CGRectGetMaxY(CGRect rect) {
return rect.origin.y + (rect.size.height < 0? 0: rect.size.height);
}
CG_EXTERN CGFloat CGRectGetWidth(CGRect rect) {
return fabs(rect.size.width);
}
CG_EXTERN CGFloat CGRectGetHeight(CGRect rect) {
return fabs(rect.size.height);
}
大部分情況下歌径,我們調(diào)用 frame.origin.x 的目的其實(shí)都是想獲取 view 最左邊的位置,其實(shí)都應(yīng)該調(diào)用 CGRectGetMinX(frame) 方法亲茅。也許你以前習(xí)慣通過 frame.origin.x 來獲取左邊的位置回铛,通過 CGRectGetMaxX(frame) 來獲取右邊的位置。這樣混合調(diào)用的代碼是存在很多隱患的克锣,只是可能并沒有體現(xiàn)出來茵肃。在這種情況你最好還是改正下自己的習(xí)慣。了解了這些后你就能根據(jù)使用場景來決定自己應(yīng)該怎么做袭祟。最后验残,對 CGRectGet 方法的好處進(jìn)行簡單總結(jié)。
- 語義生動直觀
- 代碼風(fēng)格統(tǒng)一
- 能夠獲取到view真實(shí)的位置
- 調(diào)用接口簡單