【譯】iOS 基礎:Frames、Bounds 和 CGGeometry

原文:《iOS Fundamentals: Frames, Bounds, and CGGeometry》
程康,2016 年 3 月 26 日
本文原鏈:【譯】iOS 基礎:Frames、Bounds 和 CGGeometryios

若是你習慣支持點語法的語言,要搞清楚CGPointCGSizeCGRect並不難。不過編程式定位視圖或者編寫繪圖代碼通常都很長,所以變得很難讀明白。git

在這個教程裏,我但願能澄清一些對 frames 和 bounds 的誤解,而且介紹一下CGGeometry,它是一個結構體、常量和功能的集合,能讓你更輕鬆地運用CGPointCGSizeCGRectgithub

1.數據類型

若是你剛開始接觸 iOS 或者 OS X 開發,你可能會想CGPointCGSizeCGRect究竟是什麼。CGGeometry Reference 定義了一系列幾何圖元(geometric primitives)或者說結構,咱們如今關注的是其中的CGPointCGSizeCGRect編程

大多數人應該知道,CGPoint是定義了座標系中一個點的 C 結構體。這個座標系的原點在 iOS 的左上方以及 OS X 的左下方。換句話說,縱軸方向在 iOS 和 OS X 上不同。框架

CGSize是另外一個簡單的 C 結構體,它定義了一個寬度值(width)和高度值(height)。CGRect包含一個origin(原點)字段、一個CGPoint和一個size(大小)字段,即一個CGSizeorigin(原點)和size(大小)字段一塊兒決定了一個矩形的位置和大小。ide

CGGeometry Reference 也定義了其餘類型,例如CGFloatCGVectorCGFloat就是一個float(單精度浮點型)或者double(雙精度浮點型)的typedef(類型重定義),是哪種取決於應用運行的機器結構是 32 位仍是 64 位。
<!--more-->post

2.Frames 和 Bounds

第一個要搞清楚的是一個視圖的framebounds之間的區別,由於這困擾着不少 iOS 入門開發者。不過這個區別也不復雜。spa

在 iOS 和 OS X 中,一個應用有多個座標系。好比,在 iOS 中應用窗口定位在屏幕的座標系,而窗口的每個子視圖定位在窗口的座標系。換句話說,一個視圖的子視圖老是定位在該視圖的座標系中。日誌

Framescode

如文檔中說的,視圖的frame是一個結構體,即一個CGRect,它定義了這個視圖的大小和它在父視圖中的位置,或者說父視圖座標系中的位置。看看下面的圖應該就能明白了。

Bounds

視圖的bounds屬性定義了這個視圖的大小和它在自身座標系中的位置。這意味着大多數狀況下一個視圖的 bounds 的原點都是{0,0},以下圖。視圖的bounds對於繪製這個視圖很重要。

當視圖的frame屬性被修改時,視圖的centerbounds屬性兩者或者其一也同時被改變。

CGGeometry Reference

方便的取值方法
以前提到過,CGGeometry Reference 是一個讓運用座標和矩形更方便的結構體、常量和方法的集合。你可能碰到過相似的下面的代碼片斷:

CGPoint point = CGPonitMake(self.view.frame.origin.x + self.view.frame.size.width, self.view.frame.origin.y + self.view.frame.size.height);

這樣的片斷不盡難閱讀,並且過於冗長。咱們能夠用在 CGGeometry Reference 中定義的兩個方便的方法重寫這段代碼。

CGRect frame = self.view.frame;
CGPoint point = CGPointMake(CGRectGetMaxX(frame), CGRectGetMaxY(frame));

爲了簡化以前那段代碼,咱們把視圖的frame儲存到一個叫frame的變量中,而且使用了CGRectGetMaxXCGRectGetMaxY兩個方法。這兩個方法的方法名解釋了本身的功能。

CGGeometry Reference 定義了返回一個矩形 x 軸座標、y 軸座標最小和最大值以及這個矩形中心座標的方法。另外兩個方便的取之方法是`CGRectGetWidth
CGRectGetHeight`。

建立結構體

當要建立CGPointCGSizeCGRect時,大多數人都用CGPointMake或者相似的方法。這些方法也被定義在 CGGeometry Reference 中。雖然它們的實現很是簡單,它們特別有用而且讓你少寫一些代碼。例如,CGRectMake是這樣實現的:

CGRectMake(CGFloat x, CGFloat y, CGFloat width, CGFloat height)
{
    CGRect rect;
    rect.origin.x = x; rect.origin.y = y;
    rect.size.width = width; rect.size.height = height;
    return rect;
}

修改矩形

以上提到過的方法都是 iOS 開發者熟知的,它們減小了咱們的代碼量而且讓它們可讀性增長。不過,CGGeometry Reference 也定義了一切其餘你們不太瞭解的方法。好比 CGGeometry Reference 定義了一堆修改CGRect結構的方法。讓咱們來看看其中一些。

CGRectUnion
CGRectUnion接受兩個CGRect結構體做爲參數而且返回一個可以包含這兩個矩形的最小矩形。聽起來可能沒什麼,我相信你也能夠用幾行代碼輕鬆實現這個功能,不過 CGGeometry 作的是給你提供一些方法讓你的代碼更乾淨、可讀性更強。

若是你把下面代碼片斷加到一個 view controller 的viewDidLoad方法中,你將在模擬器中看到以下結果。那個灰色的矩形就是使用CGRectUnion的結果。

// CGRectUnion
CGRect frame1 = CGRectMake(80.0, 100.0, 150.0, 240.0);
CGRect frame2 = CGRectMake(140.0, 240.0, 120.0, 120.0);
CGRect frame3 = CGRectUnion(frame1, frame2);
 
UIView *view1 = [[UIView alloc] initWithFrame:frame1];
[view1 setBackgroundColor:[UIColor redColor]];
 
UIView *view2 = [[UIView alloc] initWithFrame:frame2];
[view2 setBackgroundColor:[UIColor orangeColor]];
 
UIView *view3 = [[UIView alloc] initWithFrame:frame3];
[view3 setBackgroundColor:[UIColor grayColor]];
 
[self.view addSubview:view3];
[self.view addSubview:view2];
[self.view addSubview:view1];

CGRectDivide

另外一個有用的方法是CGRectDivide,它幫你把一個給定矩形分割成兩個。看看下面的代碼和截圖來了解它是怎麼運做的。

// CGRectDivide
CGRect frame = CGRectMake(10.0, 50.0, 300.0, 300.0);
CGRect part1;
CGRect part2;
CGRectDivide(frame, &part1, &part2, 100.0, CGRectMaxYEdge);
 
UIView *view1 = [[UIView alloc] initWithFrame:frame];
[view1 setBackgroundColor:[UIColor grayColor]];
 
UIView *view2 = [[UIView alloc] initWithFrame:part1];
[view2 setBackgroundColor:[UIColor orangeColor]];
 
UIView *view3 = [[UIView alloc] initWithFrame:part2];
[view3 setBackgroundColor:[UIColor redColor]];
 
[self.view addSubview:view1];
[self.view addSubview:view2];
[self.view addSubview:view3];

若是你不使用CGRectDivide來計算紅色和橙色矩形的話,你可能要多謝幾十行代碼。不信你就試試。

比較和包含

用下面六個方法來比較幾何結構和檢查包含關係很是簡單。

  • CGPointEqualToPoint

  • CGSizeEqualToSize

  • CGRectEqualToRect

  • CGRectIntersectsRect

  • CGRectContainsPoint

  • CGRectContainsRect

CGGeometry Reference 還有一些其餘寶貝,好比CGPointCreateDictionaryRepresentation能夠用來將一個 CGPoint 結構體轉換爲一個 CGDictionaryRefCGRectIsEmpty能夠用來檢查一個矩形的寬高是否都爲零。更多詳情請看[《CGGeometry Reference 文檔》]()。

4.福利:打印日誌

在 Xcode 控制檯打印日誌若是沒有一些輔助方法的話很麻煩。幸運的是,UIKit 框架定義了一些讓它變得很方便的方法。我每天用它們。看看下面的代碼片斷來了解它們是如何工做。並無什麼奇特的。

CGPoint point = CGPointMake(10.0, 25.0);
CGSize size = CGSizeMake(103.0, 223.0);
CGRect frame = CGRectMake(point.x, point.y, size.width, size.height);
NSLog(@"\n%@\n%@\n%@", NSStringFromCGPoint(point), NSStringFromCGSize(size), NSStringFromCGRect(frame));

還有一些方便打印仿射變換(affine transforms)(NSStringFromCGAffineTransform)、邊緣插入(NSStringFromUIEdgeInsets)、偏移(NSStringFromUIOffset)等的日誌的方便方法。

總結

iOS SDK 包含了大量開發者們不瞭解的寶貝。我但願我給大家講明白了 CGGeometry Reference 的實用性。一旦你開始使用它的那些方法,你就會開始問本身,之前沒用它怎麼活過來的。

相關文章
相關標籤/搜索