您好,登錄后才能下訂單哦!
通過前面的介紹我們已經(jīng)了解了iOS開發(fā)的基本方法和步驟實(shí)際上只要掌握了這些基本的方法和步驟我們就可以對(duì)iOS應(yīng)用進(jìn)行更多的控制。前面介紹的開發(fā)方式是使用xib或Storyboard文件設(shè)計(jì)iOS應(yīng)用界面這也是iOS開發(fā)的最主要方式在某些極端的情況下我們也有可能不使用任何界面設(shè)計(jì)文件直接通過代碼來開發(fā)UI界面。
9.5.1 不使用界面布局文件開發(fā)UI界面
如果打算使用純代碼來開發(fā)UI界面則不需要設(shè)計(jì)任何界面布局文件沒有界面布局文件也就不再需要使用自定義的視圖控制器。這樣程序可以直接在應(yīng)用程序委托對(duì)象的application: didFinishLaunchingWithOptions:方法中創(chuàng)建UIWindow和應(yīng)用程序界面——所有這些對(duì)象的創(chuàng)建都使用objective-C代碼來完成。
實(shí)例×××面布局文件開發(fā)iOS應(yīng)用
首先創(chuàng)建一個(gè)iOS的Empty Application應(yīng)用。在創(chuàng)建iOS應(yīng)用時(shí)選擇“Empty Application”項(xiàng)即可如圖9.35所示。
圖9.35 創(chuàng)建iOS的EmptyApplication應(yīng)用
對(duì)于“Empty Application”類型的iOS應(yīng)用Xcode只生成應(yīng)用程序委托類不會(huì)生成任何界面設(shè)計(jì)文件也不會(huì)生成任何控制器類。
對(duì)于打算使用純代碼開發(fā)UI界面的開發(fā)方式來說我們的應(yīng)用并不需要任何界面設(shè)計(jì)文件也不需要任何控制器。程序只要修改應(yīng)用程序委托的application:didFinishLaunchingWithOptions:方法并在該方法中創(chuàng)建UI控件然后利用這些UI控件搭建應(yīng)用程序界面即可。下面是修改過的application:didFinishLaunchingWithOptions:方法代碼。
程序清單codes/09/9.5/CodeUI/ CodeUI/FKAppDelegate.m
// 應(yīng)用程序加載完成后將會(huì)自動(dòng)回調(diào)該方法 - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions: (NSDictionary *)launchOptions { // 創(chuàng)建UIWindow對(duì)象并將該UIWindow初始化為與屏幕相同大小 self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]]; // 設(shè)置UIWindow的背景色 self.window.backgroundColor = [UIColor whiteColor]; // 創(chuàng)建一個(gè)UIViewController對(duì)象 UIViewController* controller = [[UIViewController alloc] init]; // 讓該程序的窗口加載并顯示viewController視圖控制器關(guān)聯(lián)的用戶界面 self.window.rootViewController = controller; // 創(chuàng)建一個(gè)UIView對(duì)象 UIView* rootView = [[UIView alloc] initWithFrame :[[UIScreen mainScreen] bounds]]; // 設(shè)置controller顯示rootView控件 controller.view = rootView; // 創(chuàng)建一個(gè)圓角按鈕 UIButton* button = [UIButton buttonWithType: UIButtonTypeRoundedRect]; // 設(shè)置按鈕的大小 button.frame = CGRectMake(120, 100, 80, 40); // 為按鈕設(shè)置文本 [button setTitle:@"確定" forState:UIControlStateNormal]; // 將按鈕添加到rootView控件中 [rootView addSubview:button]; // 創(chuàng)建一個(gè)UILabel對(duì)象 self.show = [[UILabel alloc] initWithFrame :CGRectMake(60 , 40 , 180 , 30)]; // 將UILabel添加到rootView控件中 [rootView addSubview:self.show]; // 設(shè)置UILabel默認(rèn)顯示的文本 self.show.text = @"初始文本"; self.show.backgroundColor = [UIColor grayColor]; // 為圓角按鈕的觸碰事件綁定事件處理方法 [button addTarget:self action:@selector(clickHandler:) forControlEvents:UIControlEventTouchUpInside]; // 將該UIWindow對(duì)象設(shè)為主窗口并顯示出來 [self.window makeKeyAndVisible]; return YES; }
上面的代碼中首先創(chuàng)建了一個(gè)UIWindow作為應(yīng)用程序的窗口接下來創(chuàng)建一個(gè)UIView作為UIWindow顯示的根視圖需要借助一個(gè)UIViewController對(duì)象。
一旦程序中有了UIView作為容器接下來代碼歸納起來相當(dāng)于只有三行此處的三行是一種歸納說法并非實(shí)際只有三行。
創(chuàng)建UI控件比如創(chuàng)建UILabel丶創(chuàng)建UIButton等。
調(diào)用addSubView:方法將UI控件添加到其他容器中。
多次調(diào)用UI控件的setter方法來設(shè)置UI控件的外觀丶行為。
上面代碼中為按鈕的觸碰事件綁定了clickHandler:事件處理方法因此程序還需要在應(yīng)用程序委托類中定義該方法。方法代碼如下
程序清單codes/09/9.5/CodeUI/ CodeUI/FKAppDelegate.m
- (void) clickHandler:(id)sender { self.show.text = @"開始學(xué)習(xí)iOS吧"; }
上面的代碼只是簡(jiǎn)單地修改show控件的文本內(nèi)容這樣即可實(shí)現(xiàn)當(dāng)用戶觸碰按鈕時(shí)動(dòng)態(tài)改變show控件的文本內(nèi)容。
運(yùn)行該程序單擊程序中的按鈕即可看到如圖9.36所示的效果。
通過上面的開發(fā)過程可以發(fā)現(xiàn)不管是通過純代碼來創(chuàng)建UI控件再將這些UI控件搭建成程序界面還是使用界面設(shè)計(jì)文件來搭建程序界面其本質(zhì)是相同的。它們的本質(zhì)都是把UI控件當(dāng)成小的積木塊然后將這些“積木塊”按自己的意愿組合在一起就可以做成iOS應(yīng)用的程序界面了。
需要指出的是使用純代碼方式來開發(fā)iOS應(yīng)用并不是最好的開發(fā)方式這種方式不僅開發(fā)步驟異常煩瑣而且所有創(chuàng)建程序界面的代碼都由應(yīng)用程序委托對(duì)象的方法負(fù)責(zé)完成這并不符合MVC設(shè)計(jì)原則因此不利于程序組件的解耦。通過學(xué)習(xí)這種開發(fā)方式我們可以更好地理解iOS應(yīng)用中應(yīng)用程序委托的作用同時(shí)也能更好地理解iOS程序界面的底層實(shí)現(xiàn)原理。
下面介紹一種更實(shí)用的代碼方式開發(fā)UI界面。
9.5.2 使用代碼創(chuàng)建UI界面
更實(shí)際的情況是在程序運(yùn)行開始時(shí)程序已經(jīng)具有一個(gè)初始的程序界面初始界面可能只包含一個(gè)UIView在程序運(yùn)行過程中程序需要根據(jù)用戶交互來動(dòng)態(tài)添加丶刪除UI控件。
在這種需求下我們可以通過Interface Builder來設(shè)計(jì)程序的初始界面接下來在程序運(yùn)行過程中可以通過代碼創(chuàng)建UI控件再將UI控件添加到相應(yīng)的父控件中即可。
實(shí)例動(dòng)態(tài)添加丶刪除標(biāo)簽
首先創(chuàng)建一個(gè)iOS的Single View Application應(yīng)用創(chuàng)建完成后該應(yīng)用將自帶一個(gè)Main.storyboard界面設(shè)計(jì)文件但我們并不打算修改該界面設(shè)計(jì)文件而是直接在程序代碼中創(chuàng)建整個(gè)UI界面程序只使用該界面文件中的UIView作為容器即可。
接下來修改控制器類在控制器類的實(shí)現(xiàn)部分創(chuàng)建整個(gè)程序界面綁定事件處理方法。下面是控制類的實(shí)現(xiàn)部分代碼。
程序清單codes/09/9.5/DynaLabel/DynaLabel/FKViewController.m
#import "FKViewController.h" // 定義FKViewController的擴(kuò)展 @interface FKViewController () // 定義一個(gè)屬性來記錄所有動(dòng)態(tài)添加的UILabel控件 @property (nonatomic, strong) NSMutableArray* labels; @end @implementation FKViewController // 定義一個(gè)變量來記錄下一個(gè)將要添加的UILabel的位置 int nextY = 80; - (void)viewDidLoad { [super viewDidLoad]; // 設(shè)置該view的背景色 self.view.backgroundColor = [UIColor grayColor]; // 初始化labels數(shù)組 self.labels = [NSMutableArray array]; // 創(chuàng)建UIButtonTypeRoundedRect類型的UIButton對(duì)象 UIButton* addBn = [UIButton buttonWithType:UIButtonTypeRoundedRect]; // 設(shè)置addBn的大小和位置 addBn.frame = CGRectMake(30, 30, 60, 40); // 為UIButton設(shè)置按鈕文本 [addBn setTitle:@"添加" forState:UIControlStateNormal]; // 為addBn的Touch Up Inside事件綁定事件處理方法 [addBn addTarget:self action:@selector(add:) forControlEvents:UIControlEventTouchUpInside]; // 創(chuàng)建UIButtonTypeRoundedRect類型的UIButton對(duì)象 UIButton* removeBn = [UIButton buttonWithType:UIButtonTypeRoundedRect]; // 設(shè)置removeBn的大小和位置 removeBn.frame = CGRectMake(230, 30, 60, 40); // 為UIButton設(shè)置按鈕文本 [removeBn setTitle:@"刪除" forState:UIControlStateNormal]; // 為removeBn的Touch Up Inside事件綁定事件處理方法 [removeBn addTarget:self action:@selector(remove:) forControlEvents:UIControlEventTouchUpInside]; [self.view addSubview:addBn]; [self.view addSubview:removeBn]; } - (void)add:(id)sender { // 創(chuàng)建一個(gè)UILabel控件 UILabel* label = [[UILabel alloc] initWithFrame: CGRectMake(80, nextY, 160, 30)]; label.text = @"瘋狂iOS講義"; // 設(shè)置該UILabel顯示的文本 [self.labels addObject: label]; // 將該UILabel添加到labels數(shù)組中 [self.view addSubview:label]; // 將UILabel控件添加到view父控件內(nèi) nextY += 50; // 控制nextY的值加50 } - (void)remove:(id)sender { // 如果labels數(shù)組中元素個(gè)數(shù)大于0表明有UILabel可刪除 if([self.labels count] > 0) { // 將最后一個(gè)UILabel從界面上刪除 [[self.labels lastObject] removeFromSuperview]; [self.labels removeLastObject]; // 從labels數(shù)組中刪除最后一個(gè)元素 nextY -= 50; // 控制nextY的值減50 } } @end
上面的代碼中第一段粗體字代碼創(chuàng)建了應(yīng)用的初始界面該初始界面只包含兩個(gè)按鈕并且程序還為這兩個(gè)按鈕綁定了事件處理方法。
該應(yīng)用的關(guān)鍵就是實(shí)現(xiàn)add:和remove:兩個(gè)方法其中add:方法中粗體字代碼負(fù)責(zé)創(chuàng)建一個(gè)UILabel控件每次創(chuàng)建的UILabel的Y坐標(biāo)并不相同并將這個(gè)UILabel控件添加到該控制器關(guān)聯(lián)的UIView內(nèi)。這樣即可實(shí)現(xiàn)每次用戶觸碰該按鈕程序界面就會(huì)添加一個(gè)UILabel控件而remove:方法中粗體字代碼則負(fù)責(zé)把labels數(shù)組的最后一個(gè)元素UILabel控件從父控件中刪除并從該數(shù)組中刪除該元素。
通過上面的程序即可實(shí)現(xiàn)通過用戶交互來動(dòng)態(tài)添加丶刪除程序界面控件。編譯丶運(yùn)行該程序并多次觸碰添加丶刪除按鈕后可能看到如圖9.37所示的動(dòng)態(tài)界面。
9.5.3 自定義UI控件
UIView控件只是一個(gè)矩形的空白區(qū)域并沒有任何內(nèi)容。iOS應(yīng)用的其他UI控件都繼承了UIView這些UI控件都是在UIView提供的空白區(qū)域上繪制外觀。
基于UI控件的實(shí)現(xiàn)原理開發(fā)者完全可以開發(fā)出項(xiàng)目定制的控件——當(dāng)iOS系統(tǒng)提供的UI控件不足以滿足項(xiàng)目需要時(shí)開發(fā)者可以通過繼承UIView來派生自定義控件。
當(dāng)開發(fā)者打算派生自己的UI控件時(shí)首先定義一個(gè)繼承View基類的子類然后重寫View類的一個(gè)或多個(gè)方法通??梢员挥脩糁貙懙姆椒ㄈ缦?。
initWithFrame:前面已經(jīng)見到程序創(chuàng)建UI控件時(shí)常常會(huì)調(diào)用該方法執(zhí)行初始化因此如果你需要對(duì)UI控件執(zhí)行一些額外的初始化即可通過重寫該方法來實(shí)現(xiàn)。
initWithCoder:程序通過在nib文件中加載完該控件后會(huì)自動(dòng)調(diào)用該方法。因此如果程序需要在nib文件中加載該控件后執(zhí)行自定義初始化則可通過重寫該方法來實(shí)現(xiàn)。
drawRect:如果程序需要自行繪制該控件的內(nèi)容則可通過重寫該方法來實(shí)現(xiàn)。
layoutSubviews如果程序需要對(duì)該控件所包含的子控件布局進(jìn)行更精確的控制可通過重寫該方法來實(shí)現(xiàn)。
didAddSubview:當(dāng)該控件添加子控件完成時(shí)將會(huì)激發(fā)該方法。
willRemoveSubview:當(dāng)該控件將要?jiǎng)h除子控件時(shí)將會(huì)激發(fā)該方法。
willMoveToSuperview:當(dāng)該控件將要添加到其父控件中時(shí)將會(huì)激發(fā)該方法。
didMoveToSuperview當(dāng)把該控件添加到父控件完成時(shí)將會(huì)激發(fā)該方法。
willMoveToWindow: 當(dāng)該控件將要添加到窗口中時(shí)將會(huì)激發(fā)該方法。
didMoveToWindow當(dāng)把該控件添加到窗口完成時(shí)將會(huì)激發(fā)該方法。
touchesBegan:withEvent:當(dāng)用戶手指開始觸碰該控件時(shí)將會(huì)激發(fā)該方法。
touchesMoved:withEvent:當(dāng)用戶手指在該控件上移動(dòng)時(shí)將會(huì)激發(fā)該方法。
touchesEnded:withEvent:當(dāng)用戶手指結(jié)束觸碰該控件時(shí)將會(huì)激發(fā)該方法。
touchesCancelled:withEvent:用戶取消觸碰該控件時(shí)將會(huì)激發(fā)該方法。
當(dāng)需要開發(fā)自定義View時(shí)開發(fā)者并不需要重寫上面列出的所有方法而是根據(jù)業(yè)務(wù)需要重寫上面的部分方法。例如下面的跟隨手指運(yùn)動(dòng)的小球示例程序就只重寫drawRect:方法。
實(shí)例跟隨手指運(yùn)動(dòng)的小球
為了實(shí)現(xiàn)一個(gè)跟隨手指運(yùn)動(dòng)的小球示例我們考慮開發(fā)自定義的UI控件這個(gè)UI控件將會(huì)在指定位置繪制一個(gè)小球這個(gè)位置可以動(dòng)態(tài)改變。當(dāng)用戶通過手指在屏幕上拖動(dòng)時(shí)程序監(jiān)聽到這個(gè)手指動(dòng)作并把手指動(dòng)作的位置傳入自定義UI控件然后通知該控件重繪即可。
首先創(chuàng)建一個(gè)Single View Application然后通過該應(yīng)用的項(xiàng)目導(dǎo)航面板打開Main.storyboard文件選中Dock區(qū)內(nèi)唯一場(chǎng)景內(nèi)的View Controller節(jié)點(diǎn)或選中界面布局文件中的根UI控件UIView也就是界面中大塊的丶右上角有個(gè)電池圖標(biāo)的白色矩形區(qū)域然后按下鍵盤上的command+option+3快捷鍵打開Xcode的身份檢查器通過身份檢查器可以看到該界面布局文件的根UI控件的實(shí)現(xiàn)類是UIView如圖9.38所示。
該應(yīng)用并不打算使用默認(rèn)的UIView作為根控件因此將圖9.38所示對(duì)話框中Class文本框內(nèi)的實(shí)現(xiàn)類改為FKCustomView這表明程序?qū)⑹褂肍KCustomView作為界面設(shè)計(jì)的根控件。
接下來程序需要開發(fā)自定義的FKCustomView類其步驟如下。
①用鼠標(biāo)右鍵單擊項(xiàng)目文件夾然后單擊“New File”菜單項(xiàng)Xcode彈出如圖9.39所示的對(duì)話框。
圖9.38 通過身份檢查器面板管理UI控件的實(shí)現(xiàn)類
圖9.39 創(chuàng)建objective-C類
②在圖9.39所示對(duì)話框的左邊選中iOS分類下的Cocoa Touch然后在對(duì)話框右邊選中“objective-Cclass”列表項(xiàng)后單擊“Next”按鈕系統(tǒng)顯示如圖9.40所示的對(duì)話框。
圖9.40 確定類名和父類
③在圖9.40所示的對(duì)話框中輸入類名選擇父類之后單擊“Next”按鈕Xcode將會(huì)顯示一個(gè)保存文件夾用于確定新創(chuàng)建文件的存儲(chǔ)路徑。選擇合適的路徑后單擊“Create”按鈕即可創(chuàng)建一個(gè)新的objective-C類。
下面是自定義控件類實(shí)現(xiàn)部分的代碼接口部分僅僅只是繼承UIView即可。
程序清單codes/09/9.5/CustomView/CustomView/FKCustomView.m
#import "FKCustomView.h" @implementation FKCustomView // 定義兩個(gè)變量記錄當(dāng)前觸碰點(diǎn)的坐標(biāo) int curX; int curY; - (void) touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event { // 獲取觸碰事件的UITouch事件 UITouch *touch = [touches anyObject]; // 得到觸碰事件在當(dāng)前組件上的觸碰點(diǎn) CGPoint lastTouch = [touch locationInView:self]; // 獲取觸碰點(diǎn)的坐標(biāo) curX = lastTouch.x; curY = lastTouch.y; // 通知該組件重繪 [self setNeedsDisplay]; } // 重寫該方法來繪制該UI控件 - (void)drawRect:(CGRect)rect { // 獲取繪圖上下文 CGContextRef ctx = UIGraphicsGetCurrentContext(); // 設(shè)置填充顏色 CGContextSetFillColorWithColor(ctx, [[UIColor redColor] CGColor]); // 以觸碰點(diǎn)為圓心繪制一個(gè)圓形 CGContextFillEllipseInRect(ctx, CGRectMake(curX - 10, curY - 10, 20, 20)); } @end
上面的程序自定義了UIView的子類FKCustomView該子類重寫了drawRect:方法該方法的邏輯很簡(jiǎn)單它僅僅只是以觸碰點(diǎn)為圓心繪制一個(gè)圓形。除此之外該自定義UIView子類還重寫了touchesMoved方法每當(dāng)用戶觸碰該組件時(shí)程序就會(huì)將觸碰點(diǎn)的坐標(biāo)賦給curX丶curY兩個(gè)變量并通知該控件調(diào)用drawRect:方法來重繪自身。這樣即可保證每當(dāng)用戶觸碰該控件時(shí)該控件總會(huì)在觸碰點(diǎn)繪制一個(gè)紅色圓形。
編譯丶運(yùn)行該程序即可看到如圖9.41所示的效果。
——本文節(jié)選自《瘋狂ios講義上》
免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如果涉及侵權(quán)請(qǐng)聯(lián)系站長(zhǎng)郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。