張 華,楊凱淇
(1.長春工程學院計算機技術(shù)與工程學院,長春 130012;2.哈爾濱工業(yè)大學電氣工程及自動化學院,哈爾濱 150001)
iOS APP中框架的搭建及TabBar的自定義創(chuàng)建的分析
張 華1,楊凱淇2
(1.長春工程學院計算機技術(shù)與工程學院,長春 130012;2.哈爾濱工業(yè)大學電氣工程及自動化學院,哈爾濱 150001)
在設(shè)計一個iOS APP時,首先要分析其所有的功能并進行按模塊劃分,然后要根據(jù)劃分出來的模塊進行整體框架的搭建和TabBar的設(shè)計,兩者的合理設(shè)計對整個APP有重要影響,以新浪微博為例,詳細介紹了APP中框架的搭建和TabBar的自定義創(chuàng)建。
iOS APP;框架;TabBar;新浪微博
在當今互聯(lián)網(wǎng)時代,智能手機廣泛應(yīng)用,人們工作、生活、學習中的很多方面都可以通過網(wǎng)絡(luò)借助手機APP來完成,比如:微信、大眾點評、騰訊視頻、扇貝單詞等,可以說,手機APP已經(jīng)變成人們工作和生活中不可或缺的一部分,也使得APP開發(fā)有很大的市場。在開發(fā)APP時,因為各自功能和業(yè)務(wù)邏輯都不相同,具體實現(xiàn)過程也就不同,但開發(fā)思路都是一樣的,整個APP的框架搭建和主功能欄TabBar的實現(xiàn)至關(guān)重要,本文借助于新浪微博APP就這兩方面進行闡述,掌握了這兩方面的技巧,也就可以得心應(yīng)手地去開發(fā)各類APP。
在設(shè)計智能終端APP時,整體框架的搭建相當于是APP的靈魂,一個合適的框架,不但能保證工程可以順利進行,還能夠降低通用問題的復雜度和減少發(fā)生錯誤的可能性,現(xiàn)在流行的APP架構(gòu)主要有MVC和MVVM。
1.1 MVC架構(gòu)
MVC:Model-View-Controller,模型Model通常是Core Data managed objects,包括數(shù)據(jù)和操作數(shù)據(jù)的業(yè)務(wù)邏輯;視圖View通常是UIKit控件或者編碼定義的UIKit控件的集合,比如:Button、Label,View不直接引用Model,并且僅僅通過IBAction事件引用Controller,業(yè)務(wù)邏輯不歸入view,視圖本身沒有任何業(yè)務(wù);控制器Controller負責協(xié)調(diào)模型和視圖之間的所有交互。

圖1 MVC架構(gòu)
在上圖中,View將用戶交互通知給Controller。View Controller通過更新Model來反應(yīng)狀態(tài)的改變。Model(通常使用Key-Value-Observation)通知Controller來更新它們負責的View。大多數(shù)iOS應(yīng)用程序的代碼使用這種方式來組織。
1.2 MVVM架構(gòu)
在MVC模式的iOS開發(fā)中,Controller承擔了太多的代碼,包含著視圖處理邏輯和業(yè)務(wù)邏輯。MVVM:Model-View-ViewModel,這種模型通常應(yīng)用在UIKit控件不能設(shè)置固定高度,必須根據(jù)顯示內(nèi)容多少而決定的情況下。View Model用來放置用戶輸入驗證邏輯、視圖顯示邏輯、發(fā)起網(wǎng)絡(luò)請求等代碼。

圖2 MVVM架構(gòu)
在上圖中,View和View Controller聯(lián)系在一起,可以把它們視為一個組件。視圖View仍然不能直接引用模型Model,控制器Controller也不能,但是它們都可以引用視圖模型View Mode。在MVVM中,將視圖處理邏輯從C中剝離出來給V,剩下的業(yè)務(wù)邏輯部分被稱做View-Model。使用MVVM模式的iOS應(yīng)用的可測試性要好于MVC,因為ViewModel中并不包含對View的更新,相比于MVC,減輕了Controller的負擔,使功能劃分更加合理。MVVM模式的正確實踐是,應(yīng)該為App Delegate的根視圖創(chuàng)建一個ViewModel,當我們要生成或展示另一個次級ViewController時,采用當前的ViewModel為其創(chuàng)建一個子ViewModel。
1.3 新浪微博的框架搭建
大家所熟悉的新浪微博的主界面,如圖3所示,主功能分為五大模塊:首頁、消息、發(fā)現(xiàn)、我、還有中間的“+”(即發(fā)微博)。

圖3 新浪微博主界面
按照微博APP的主功能設(shè)計,將項目中的文件按照MVC框架進行劃分,每個模塊都細分為MVC 3部分,擴展分類、網(wǎng)絡(luò)訪問、第三方組件、基礎(chǔ)工具類、圖片等都分別存放,具體劃分如圖4所示:具體文件夾說明如下:
1)Classes:APP類文件都存放在此文件夾,包含以下子文件夾:
Main:存放APP主界面文件,如:TabBar;
Home:存放“首頁”模塊中的所有文件;
Message:存放“消息”模塊中的所有文件;
Discover:存放“發(fā)現(xiàn)”模塊中的所有文件;
Profile:存放“我”模塊中的所有文件;
Compose:存放“+”模塊,即發(fā)微博模塊中的所有文件;
Setting:存放個人設(shè)置模塊中的所有文件;
Newfeature:存放新特性模塊中的所有文件;
OAuth:存放授權(quán)模塊中的所有文件;

圖4 微博項目文件結(jié)構(gòu)
以上文件夾下均包含Model、View、Controller 3個子文件夾分別用來存放各模塊的模型、視圖和控制器。
Base:存放通用、基礎(chǔ)功能的文件;
Tool:存放各種業(yè)務(wù)邏輯的操作文件,如:網(wǎng)絡(luò)訪問的各文件;
Other:訪問各種其他文件,如分類文件、第三方組件、APP啟動文件AppDelegate等。
2)images:存放普通圖片。
3)Assets.xcassets:管理應(yīng)用的Icon和Default圖片,自動管理圖片。
4)Supporting Files:存放APP配置文件等輔助文件。
每個文件夾下都可以根據(jù)功能設(shè)計再劃分各子文件夾,這樣劃分,層次清楚、邏輯清晰,可以靈活地管理各個模塊,也可以方便地替換網(wǎng)絡(luò)訪問層和第三方組件,以便完成APP更新升級。
2.1 系統(tǒng)自帶的TabBar
在APP的啟動文件AppDelegate中需要設(shè)置要啟動的TabBarController,即工具條控制器,APP界面下方的工具條稱為TabBar,高度固定為49,如果TabBarController有N個子控制器,那么TabBar內(nèi)部就會有N個TabBarButton作為子控件與之對應(yīng),TabBarButton在TabBar中的位置是均分的,TabBarButton里面顯示什么內(nèi)容,由對應(yīng)子控制器的TabBarItem屬性來決定,TarBarButton右上角顯示更新數(shù)目的稱為BadgeView,如圖5~6所示:

圖5 微信APP界面底部的TabBar

圖6 微博APP界面底部的TabBar
圖5中的TabBar實現(xiàn)方法較為簡單,可以直接使用系統(tǒng)自帶的TabBar來完成,分別創(chuàng)建各個TabBarButton對應(yīng)的TabBarController,然后添加到TabBarController中即可,使用系統(tǒng)自帶的TabBar創(chuàng)建微博APP的TabBar,大致代碼如下:
-(void)setUpAllChildViewController{
//首頁
UIViewController *home=[[UIViewControlleralloc]init];
[self setUpOneChildViewController:home image:[UIImageimageNamed:@"tabbar_home"] selectedImage:[UIImageimageWithOriginalName:@"tabbar_home_selected"] badgeValue:@"10" title:@"首頁"];
//消息
UIViewController*message=[[UIViewControlleralloc]init];
[self setUpOneChildViewController:message image:[UIImageimageNamed:@"tabbar_message_center"] selectedImage:[UIImageimageWithOriginalName:@"tabbar_message_center_selected"] badgeValue:@"10" title:@"消息"];
//發(fā)現(xiàn)
UIViewController*discover=[[UIViewControlleralloc]init];
[self setUpOneChildViewController:discover image:[UIImageimageNamed:@"tabbar_discover"] selectedImage:[UIImageimageWithOriginalName:@"tabbar_discover_selected"] badgeValue:@"10" title:@"發(fā)現(xiàn)"];
//我
UIViewController*profile=[[UIViewControlleralloc]init];
[self setUpOneChildViewController:profile image:[UIImageimageNamed:@"tabbar_profile"] selectedImage:[UIImageimageWithOriginalName:@"tabbar_profile_selected"] badgeValue:@"10" title:@"我"];
}
-(void)setUpOneChildViewController:(UIViewController *)vc image:(UIImage *)image selectedImage:(UIImage *)selectedImage title:(NSString *)title {
vc.title=title; //設(shè)置當前VC的標題,顯示在導航欄中
vc.tabBarItem.title=title;
vc.tabBarItem.image=image; //設(shè)置圖片
vc.tabBarItem.selectedImage=selectedImage;
//將每個VC的tabBarItem添加到items數(shù)組中
[self.itemsaddObject:vc.tabBarItem];
}
2.2 自定義的TabBar
系統(tǒng)自帶的TabBar不能更改TabBarButton上的BadgeView,因為其繼承自UIView且沒有更改image的屬性或者方法,所以只能使用BadgeView的默認效果,通常情況下,這種效果不能滿足大眾需要,另外,圖6中的TabBar除了四個普通的TabBarButton外,中間還有一個自定義的按鈕“+”,這種情況下,系統(tǒng)自帶的TabBar也無法實現(xiàn)。綜合以上兩方面的原因,需要自定義TabBar重新封裝,此次封裝既解決BadgeView的問題,也替換了TabBar中的各個按鈕。自定義創(chuàng)建TabBar的步驟如圖7所示。
在單擊TabBar上的各個按鈕實現(xiàn)界面切換時,實際上是在TabBar視圖上單擊按鈕,在TabBarController上實現(xiàn)控制器的切換,所以要在TabBar視圖中聲明協(xié)議和代理,在TabBarController上通過代理完成協(xié)議中的方法。
自定義TabBar的具體步驟及相關(guān)代碼如下:
1)創(chuàng)建每個按鈕對應(yīng)的ViewController:在Main文件夾的Controller文件夾上分別創(chuàng)建WBHomeViewController(首頁)、WBMessageViewController(消息)、WBDiscoverViewController(發(fā)現(xiàn))、WBProfileViewController(我)、WBComposeViewController(發(fā)微博“+”),繼承自UITableViewController。
2)創(chuàng)建主視圖控制器TabBarViewController:在Main文件夾的Controller文件夾上創(chuàng)建WBTabBarController,繼承自UITabBarViewController,聲明一個items數(shù)組來保存每個子控制器的tabBarItem,items要使用懶加載。引用步驟(1)中創(chuàng)建的各子控制器并聲明對應(yīng)的對象,調(diào)用之前的setUpAllChildViewController實現(xiàn)各子控制器的加載,修正之前的在此方法中需要將原來的UIViewController更改為各具體的子控制器。大致代碼如下:

圖7 自定義TabBar的創(chuàng)建步驟
@property(nonatomic,strong)NSMutableArray*items;
@property(nonatomic,strong)WBHomeViewController*home;
-(void)setUpAllChildViewController{
//首頁
WBHomeViewController*home=[[WBHomeViewControlleralloc]init];
[self setUpOneChildViewController:home image:[UIImageimageNamed:@"tabbar_home"] selectedImage:[UIImageimageWithOriginalName:@"tabbar_home_selected"] badgeValue:@"10" title:@"首頁"];
_home=home;
……
}
setUpOneChildViewController方法在原來的代碼的基礎(chǔ)上要增加為items數(shù)組賦值。
-(void)setUpOneChildViewController:(UIViewController *)vc image:(UIImage *)image selectedImage:(UIImage *)selectedImage title:(NSString *)title {
…..
//將每個VC的tabBarItem添加到items數(shù)組中
[self.itemsaddObject:vc.tabBarItem];
}
3)創(chuàng)建TabBar視圖:在Main文件夾的View上新建WBTabBar類,繼承自UIView而不是UITabBar。聲明一個items數(shù)組,用來接收WBTabBarController中傳遞過來的包含各子控制器tabBarItem的items數(shù)組,根據(jù)此數(shù)組來設(shè)定在TabBar上顯示的TabBarButton的數(shù)量及內(nèi)容。
4)創(chuàng)建顯示未讀數(shù)目的BadgeView按鈕:在Main文件夾的View文件夾上新建WBBadgeView文件,繼承自UIButton。在.h頭文件里,設(shè)置一個badgeValue屬性,屬于NSString對象,重寫initWithFrame方法實現(xiàn)按鈕的創(chuàng)建及初始化,重寫badgeValue的set方法,每當有值傳過來的時候都會調(diào)用這個方法,刷新Button上顯示的信息,在代碼中要判斷傳入來的badgeValue值是否為空或者是0,以此決定Button上是否顯示,然后根據(jù)傳入文字的大小,決定應(yīng)該顯示什么圖片。
5)創(chuàng)建自定義TabBarButton按鈕:在Main文件夾的View上新建WBTabBarButton類,繼承自UIButton。在頭文件里聲明UITabBarItem對象item來保存從TabBar內(nèi)得到的TabBarItem模型,根據(jù)模型可以設(shè)置每個按鈕的內(nèi)容。在每個按鈕的右上方需要顯示未讀數(shù)目,需要引入步驟4)中創(chuàng)建的WBBadgeView,然后重寫initWithFrame設(shè)置按鈕的文字和圖片等基本信息,重寫layOutSubviews方法調(diào)整文字、圖片的尺寸和位置。大致代碼如下:
@property(nonatomic,weak)WBBadgeView *badgeView;
-(WBBadgeView *)badgeView
{
if(_badgeView == nil){
WBBadgeView *badgeView = [WBBadgeViewbuttonWithType:UIButtonTypeCustom];
[selfaddSubview:badgeView];
_badgeView = badgeView;
}
return _badgeView;
}
6)給自定義的TabBarButton添加監(jiān)聽事件:使用KVO監(jiān)聽TabBarItem的屬性,當模型更改的時候,視圖也跟著更改。系統(tǒng)默認模型改變的時候,不刷新視圖,需要手動調(diào)用KVO,在對象被銷毀時,清空觀察者。重寫item 的set方法,傳遞UITabBarItem的信息給WBTabBarButton并實現(xiàn)監(jiān)聽。
7)設(shè)置自定義WBTabBar視圖中的協(xié)議和代理:聲明一個數(shù)組buttons用來保存視圖中的所有按鈕,給每個TabBarButton添加監(jiān)聽按鈕點擊的方法,4個普通按鈕和1個“+”按鈕分別添加,以用于控制器的切換。因為控制器的切換是由WBTabBarController控制的,所以需要給WBTabBar添加代理屬性,4個普通按鈕和1個“+”按鈕分別添加,兩個代理,在TabBarButton點擊時,會通知WBTabBarController切換控制器。在四個普通按鈕的代理方法中設(shè)定角標參數(shù),把按鈕的tag傳遞出去。頭文件.h文件中的大致代碼如下:
//設(shè)置代理
@class WBTabBar;
@protocol WBTabBarDelegate
@optional
//規(guī)定協(xié)議中要完成的動作即代理要實現(xiàn)的方法,即回調(diào)函數(shù),在外界的ViewController中要具體實現(xiàn)
-(void)tabBar:(WBTabBar *)tabBardidSelectedIndex:(NSInteger)selectedIndex;
-(void)tabBarDidClickAddBtn:(WBTabBar *)tabBar;
@end
@interface WBTabBar : UIView //由原來的UITabBar更改為UIView
// items:保存每一個按鈕對應(yīng)tabBarItem模型
@property(nonatomic,strong)NSArray *items;
@property(nonatomic,weak)id
@end
8)在WBTabBarController中完成協(xié)議中規(guī)定的方法:遵守WBTabBar中規(guī)定的協(xié)議,WBTabBarController成為WBTabBar的代理,實現(xiàn)協(xié)議里規(guī)定的兩個代理方法,大致代碼如下:
@interface WBTabBarController()
@property(nonatomic,assign)NSIntegerselIndex;//保存被選中按鈕的tag
//重寫WBTabBar協(xié)議中的代理方法,當在WBTabBar中監(jiān)聽到TabBar被點擊時就會調(diào)用此方法
-(void)tabBar:(WBTabBar *)tabBardidSelectedIndex:(NSInteger)selectedIndex
{
self.selectedIndex = index;
}
// 重寫WBTabBar協(xié)議中代理方法,當在WBTabBar中監(jiān)聽到"+"被點擊時就會調(diào)用此方法
-(void)tabBarDidClickAddBtn:(WBTabBar*)tabBar
{
//具體完成點擊發(fā)微博按鈕時的動作
}
到此為止,自定義的TabBar工具條就實現(xiàn)了。
MVVM框架是對MVC的改進,可以跟 storyboard一樣用來顯示高度不固定的內(nèi)容,自定義TabBar對初學者可能比較繞,本質(zhì)上就是一層一層的值傳遞,直到把值傳遞給最應(yīng)該需要的那個控件或者類,這是一種正向思維,還有一種是逆向思維,直接推測WBTabBarButton需要什么樣的值才能建立好所需要展示的TabBarButton。一想便知它需要圖片、文字等信息,而思考這些信息保存在哪里,如何能得到,便是一種逆向思維。無論使用哪種思維,只要思路清晰、邏輯正確,就可以創(chuàng)建出各式各樣的自定義TabBar。
[1] 唐巧.iOS開發(fā)進階[M]. 北京:電子工業(yè)出版社,2014.
[2] 納皮爾,庫瑪.iOS編程實戰(zhàn)[M]. 北京:人民郵電出版社,2014.
[3] 李宜為.基于iOS自由行客戶端的設(shè)計與實現(xiàn)[D].北京:北京交通大學2015.
The Construction of iOS APP Framework and the Analysis of the Self-defined Creation of Tab Barin
ZHANG Hua,et al.
(SchoolofComputerTechnology&Engineering,ChangchunInstituteofTechnology,Changchun130012,China)
During the design an iOS APP,all the functions should be firstly analyzed and module classifications should be made.Then the whole framework construction and Tab Bar design should be done according to the classified modules.The reasonable design to both parts is important to the whole APP.Taking Sina Weibo as an example,this paper introduces in detail the framework construction in APP and the self-defined creation of Tab Bar.
iOS APP;framework;TabBar;SinaWeibo
10.3969/j.issn.1009-8984.2016.04.026
2016-11-08
張華(1981-),女(漢),山東泰安,講師,碩士 主要研究數(shù)字圖像處理、數(shù)據(jù)挖掘。
TP391
A
1009-8984(2016)04-0100-05