使用CGGeometry方法獲取CGRect數(shù)據(jù)

CGGeometry 中提供了取特定 CGRect 值的便捷方法。

  • CGRectGetMinX
  • CGRectGetMinY
  • CGRectGetMidX
  • CGRectGetMidY
  • CGRectGetMaxX
  • CGRectGetMaxY
  • CGRectGetWidth
  • CGRectGetHeight

這其中CGRectGetMidX,CGRectGetMidY,CGRectGetMaxX,CGRectGetMaxY四個(gè)方法十分有用。用CGRectGetMaxX代替frame.origin.x + frame.size.width將使代碼更加清晰、語(yǔ)義上也更為生動(dòng)直觀。另外三個(gè)方法也同樣,他們都可以用來(lái)代替類似這樣的代碼。

  • CGRectGetMidX用來(lái)替代frame.origin.x + frame.size.width / 2
  • CGRectGetMidY用來(lái)替代frame.origin.y + frame.size.height / 2
  • CGRectGetMaxX用來(lái)替代frame.origin.x + frame.size.width
  • CGRectGetMaxY用來(lái)替代frame.origin.y + frame.size.height

這時(shí)你也許會(huì)想到,那CGRectGetMinX,CGRectGetMinY,CGRectGetWidth,CGRectGetHeight四個(gè)方法是不是也是用來(lái)代替類似這樣的代碼。

  • CGRectGetMinX用來(lái)替代frame.origin.x
  • CGRectGetMinY用來(lái)替代frame.origin.y
  • CGRectGetWidth用來(lái)替代frame.size.width
  • CGRectGetHeight用來(lái)替代frame.size.width

答案是肯定的。但這四個(gè)方法看起來(lái)卻不是那么有必要。因?yàn)楦苯诱{(diào)用相比,這樣寫代碼要更長(zhǎng)。

  • CGRectGetMinX(frame)
  • frame.origin.x

而且如果想要喚起 Xcode 的聯(lián)想,最少需要輸入“CGRectGet”八個(gè)字母。而直接調(diào)用通常只需要輸入“f”,“.o”,“.x”五個(gè)字母就能聯(lián)想完成。經(jīng)過性能測(cè)試,CGRectGetMinX(frame) 的億次調(diào)用耗時(shí)561毫秒,而直接調(diào)用由于不明原因,不管循環(huán)多少次測(cè)試調(diào)用時(shí)間都低于1毫秒。竟然代碼更長(zhǎng),輸入更慢,效率更低,那 CGGeometry 提供這些接口的意義在哪呢。其實(shí),僅憑代碼統(tǒng)一的代碼風(fēng)格,生動(dòng)直觀的語(yǔ)義也值得你這樣去做。而且效率上的差異只是理論數(shù)值,實(shí)際上CGRectGet的10萬(wàn)次調(diào)用只耗時(shí)1毫秒,在整個(gè)APP的運(yùn)行期間也很難有超過10萬(wàn)次的調(diào)用。

蘋果官方文檔推薦使用 CGGeometry 方法,同時(shí)盡量避免直接調(diào)用。事實(shí)上僅僅因?yàn)樯鲜龅倪@些好處蘋果是不會(huì)建議盡量避免直接調(diào)用的,這兩種調(diào)用方法其實(shí)存在這本質(zhì)的差異。在平時(shí)的使用中我們沒有遇到差異,是因?yàn)槲覀兪褂玫?frame 或 bounds 通常都是正數(shù),當(dāng)負(fù)數(shù)出現(xiàn)的時(shí)候,有意思的事情就來(lái)了。

StackOverflow摘自蘋果郵件列表的原文說(shuō)明了這個(gè)現(xiàn)象。大意就是“CGRectGetWidth/Height 會(huì)將 width 或者 height 格式化,格式化基本上只是檢查 width 或者 height 是否為負(fù)數(shù),如果為負(fù)數(shù)則取絕對(duì)值”。下邊就來(lái)解釋這個(gè)現(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 是用來(lái)儲(chǔ)存矩形幾何信息的容器,通過這些信息就能知道怎么去繪制矩形。UIView 通過 CGRect 類型的成員變量 frame 來(lái)描述自己的位置和形狀。通過 CGRectGet 方法獲取到的是 view 的實(shí)際位置和形狀,而直接調(diào)用獲取的只是描述幾何體位置和形狀的信息,他們的是帶有方向性的。比如,view 的寬是-100,代表的是在 x 軸反方向的100,最終繪制出來(lái)矩形的寬還是100,只是在 x 軸負(fù)方向而已。所以,通過 CGRectGetWidth(frame) 獲取到的就是真實(shí)的寬度100,而直接調(diào)用只能獲取同時(shí)描述寬度和方向的數(shù)值-100。這看起來(lái)只是取絕對(duì)值這么簡(jiǎn)單,但其他方法可并不是這樣。通過如下代碼繪制出來(lái)下圖所示的兩個(gè) 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;
CGRect.png

通過圖片顯而易見,使用 CGRectGetMinX 獲取到的是 viewB 顯示在屏幕上最左邊位置,就是-150。而通過 frame.origin.x 獲取到的必然是-50。簡(jiǎn)單來(lái)說(shuō),只要 width 或者 height 是負(fù)數(shù),那么這個(gè) view 的左右或者上下其實(shí)是翻轉(zhuǎn)過的。你之前用直接調(diào)用的方法(frame.origin.x + frame.size.width)去獲取的(-50 - 100 = -150)其實(shí) view 左邊。

代碼打印出來(lái) 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 來(lái)獲取左邊的位置,通過 CGRectGetMaxX(frame) 來(lái)獲取右邊的位置。這樣混合調(diào)用的代碼是存在很多隱患的,只是可能并沒有體現(xiàn)出來(lái)。在這種情況你最好還是改正下自己的習(xí)慣。了解了這些后你就能根據(jù)使用場(chǎng)景來(lái)決定自己應(yīng)該怎么做。最后,對(duì) CGRectGet 方法的好處進(jìn)行簡(jiǎn)單總結(jié)。

  1. 語(yǔ)義生動(dòng)直觀
  2. 代碼風(fēng)格統(tǒng)一
  3. 能夠獲取到view真實(shí)的位置
  4. 調(diào)用接口簡(jiǎn)單

參考資料

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容