和我一起來學iOS(三)UIView及其子類(上)


在開始前,我想大家應該先讀一讀 Mac OS X 背后的故事,是一篇非常不錯的文章。了解曾經發生的過去,才能對現在為什么會是這樣有更深刻的認識。

xib與nib的淵源

Project Builder 在 Mac OS X 10.3 時被重命名為現在大家所熟知的 Xcode。Xcode 3以前,Interface Builder 使用一種名為 nib 格式的二進制文件格式。不過由於 nib 不能用肉眼讀,也不方便使用版本管理工具來管理,所以 Xcode 3 開始新加入一種名為 xib 的文本文件格式,最后再在項目編譯階段輸出為 nib 格式。和產生靜態界面布局代碼的工具很不同,nib 是不被轉譯成相應 Objective-C 代碼的。用戶程序執行時,nib 文件被讀入,解包,所以 nib 文件是在運行時動態加載的。


UIView類代表的含義

UIView繼承於UIResponder類,因此它主要表達了兩個意思

1.可視(CALayer)
2.可互交(UIResponder)

每個UIView都有一個隱式層(implicit Layer),View本身就是這個隱式層的Delegate.
為什么要有層這個東西?因為作圖等都是在層上完成,然后再合成。因為UIView有了Layer所以才能顯示。

Layer又有兩部分組成。present layer和Model layer.
present layer表示了中間的過程狀態,而Model layer則表示了起始和結束狀態

初始化方法

- (id)initWithFrame:(CGRect)frame

其中frame指定了這個View的大小和位置,起始點在左上角。

 

 

UIView的子類

一、UIWindow

UIWindow是作為包含了其他所有View的一個容器。每一個程序里面都會有一個UIWindow。下面這段代碼里我們在程序啟動完成后實例化了一個UIWindow類,並調用了它的makeKeyAndVisible方法。這個方法使得window在屏幕上可見。

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
  self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]]; 
  self.window.backgroundColor = [UIColor whiteColor]; 
  [self.window makeKeyAndVisible];   
return YES; }

 
讓View顯示在屏幕上

一旦window在屏幕上可見了,之后任何加入window的view都會在屏幕上可見。換句話說,要使得一個view在屏幕上可見,需要把它加入到window之中。
當一個view被加入到window的時候,那么這個view就被稱為window的subview。每一個view都可以有自己的subview。Window是這個層級結構中的根節點。前面說了一個view如果想被顯示到屏幕上,就需要作為window的subview。除了直接加入window的subview之外,作為已經加入window的view的subview也算是間接作為window的subview,因此也可以顯示在屏幕上。
 
結構可以參照下圖(圖來自iOS Programming 3rd),MKMapView作為UIWindow的subview, UITextfield和UIButton又作為MKMapView的subview, 最終他們都顯示在了屏幕上。


這種層級關系可以直接調用UIView類的addSubview方法來實現,比如

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
  self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]]; 
  MyView *view = [[MyView alloc] initWithFrame:viewFrame]; 
  [[self window] addSubview:view];
  [self.window makeKeyAndVisible];
  return YES;
}



也可以通過界面編輯器(Interface Builder)生成xib文件,然后我們通過UIViewController加載這個xib來實現。這就是MVC模式中C和V的關系,Controller通過連線的方式持有View的引用。當然直接通過實例化的方式持有,完全不使用Interface Builder也是可以的。

我們在項目中會有一個叫MyViewController以.xib作為擴展名的文件,我們之所以用這種結合了Interface Builder的方式去初始化一個Controller,是為了讓這個Controller能方便的響應它所持有的View的所觸發的事件。下節講UITableView的時候會詳細講解。

- (id)initWithNibName:(NSString *)nibName bundle:(NSBundle *)bundle {
  self = [super initWithNibName:@"MyViewController" bundle:appBundle];

  return self; 
}

然后把這個controller作為window的rootViewController, 就可以顯示了。框架會自動把UIViewController所持有的View加入到window的subviews里。





 

drawRect方法,決定了View長啥樣

默認情況下,draRect: 方法啥都不做,交給UIView的子類去實現這個方法,讓子類有不同的樣子。例如,UIButton的drawRect:方法可以繪制一個圓角的四方形,並在正中顯示標題字符串。當你覆蓋drawRect方法的時候,系統會為View准備一個graphics context, 接着系統會激活這個context,然后調用需要繪圖的UIView對象的drawRect方法。我們可以通過UIGraphicsGetCurrentContext方法來獲取已經激活的context, 這個context的類型就是CGContextRef,它負責合並然后生成一個image。這個image就是View最終的樣子。

- (void)drawRect:(CGRect)dirtyRect {
  CGContextRef ctx = UIGraphicsGetCurrentContext(); 
  CGRect bounds = [self bounds];   center.x = bounds.origin.x + bounds.size.width / 2.0;
  center.y = bounds.origin.y + bounds.size.height / 2.0;   float maxRadius = hypot(bounds.size.width, bounds.size.height) / 4.0;   CGContextStrokePath(ctx); }

 

我們在子類覆蓋了這個方法以后,初始化這個子類就能得到下圖

 

 

 
因為drawRect挺重要,所以接下來的文章里會有對這個方法的詳細講解。



免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM