框架依舊在快速更新著:在重構、簡化代碼,統一標準的過程中。中間也遇到各種坑,不過好在一步一腳印的解決了。雖然還有些功能還在思考,不過教程,還是得補上:這篇就寫寫StartController,實現的代碼雖少,但原理很精彩!!! ...
前言:
框架依舊在快速更新著:在重構、簡化代碼,統一標準的過程中。
中間也遇到各種坑,不過好在一步一腳印的解決了。
雖然還有些功能還在思考,不過教程,還是得補上:
上篇文章:Sagit.Framework For IOS 開發框架入門開發教程2:一行代碼實現引導頁
裡面講到,引導完後,根據是否存在的Token來解決跳轉到StartController還是MainController。
這篇就寫寫StartController,實現的代碼雖少,但原理很精彩!!!
Sagit 實現登陸註冊引導頁
從WelcomleController中,現在跳到了StartController了:
呈現的內容如下圖:(為不影響整體,這圖寬高設的的很小,大伙可以新開視窗看大圖):
這個界面,除了基礎的佈局,還有兩個事件:
1:點立即註冊:跳轉到註冊頁。
2:點登錄:或跳轉到登錄頁。
整體的效果如下:
這裡把View和Controller分開文件處理:
看看StartView的佈局的全部代碼:(下麵是我本人簡化後的代碼,以前的代碼多到嚇死人)
#import "STView.h" @interface StartView : STView //StartView.h @end @implementation StartView //StartView.m - (void)initUI {
if(self.STController!=nil && self.STController.navigationController==nil){
[self.STController asRoot:RootViewNavigationType];}
[self needNavigationBar:NO setNavBar:YES];//隱藏導航欄。 [[[self addImageView:@"logo" imgName:@"login_logo"] width:170 height:170] relate:LeftTopRight v:290 v2:200 v3:290]; UILabel *title = [[[self addLabel:nil text:@"IT戀" font:48] width:160 height:44] onBottom:@"logo" y:50]; [[title textColor:@"#000000"] textAlignment:NSTextAlignmentCenter]; UILabel *description = [[[[self addLabel:nil text:@"找優質靠譜IT男就上IT戀" font:36] width:450 height:34] onBottom:title y:48] toCenter:X]; [[description textColor:@"#000000"] textAlignment:NSTextAlignmentCenter]; UIButton *regBtn = [[[[self addButton:@"Reg" title:@"立即註冊"] width:287 height:77] onBottom:description y:484] toCenter:X]; [[regBtn backgroundImage:@"login_btn"] keyValue:@{@"leftNavImage":@"nav_arrow_left_black"}]; UIButton *loginBtn = [[[[self addButton:@"Login" title:@"已有賬號,立即登錄" font:24] width:300 height:26] onBottom:regBtn y:60] toCenter:X]; [[loginBtn titleColor:MainHexColor] keyValue:STPreView.keyValue]; } @end
代碼功能講解(第二點和第三點下麵再細講):
1:基本上一個控制項佈局就一行代碼,直接看過去就好了。 2:第一行設置不需要導航欄,並直接隱藏導航欄:[self needNavigationBar:NO setNavBar:YES];//隱藏導航欄 3:註冊和登陸按鈕,多了一個陌生的keyValue,因為這裡要控制導航的返回按鈕為自定義的圖片。
再看看StartController中的全部代碼:
@interface StartController : STController //StartController.h
@end @implementation StartController //StartContrller.m -(instancetype)init { //初始化全局設置,必須要在UI初始之前。 [self configNavAndStatusBar]; return self; } -(void)configNavAndStatusBar {
[[UIApplication sharedApplication] setStatusBarStyle:UIStatusBarStyleDefault animated:YES];//白色底,所以狀態字顏色改為黑 //這裡提前統一設定全局協議的內容(對於登陸、註冊、找回密碼三個窗體有效),進入Main之後,會重新修改全局協議的內容 [[[[[[UINavigationBar globalSetting] barTintColor:ColorWhite]tintColor:ColorBlack] backgroundImage:nil] shadowImage:nil] titleTextAttributes:@{NSForegroundColorAttributeName:ColorBlack}];
}
功能講解:
1:設置全局的導航欄和狀態欄屬性。
2:如果當前不是導航控制器,則設置自身為導航根控制器。
Sagit 框架講解:佈局
對於框架的佈局:
1:以【self addXXX】為起手勢,一行代碼實現一個UI的佈局。 2:對於需要特定類型的控制屬性的,用變數接收後,用無限連語法處理屬性賦值。 3:相對父控制項,用relate方法;相對同級,用:onTop、onLeft、onRight、onBottom方法,可以混著用,怎麼簡單怎麼來。
佈局的方法,都抽到了以下STUIViewAutoLayout文件中:
看看基本的方法重載:
#pragma mark [相對佈局方法] RelativeLayout -(UIView*)onRight:(id)uiOrName x:(CGFloat)x; -(UIView*)onRight:(id)uiOrName x:(CGFloat)x y:(CGFloat)y; -(UIView*)onLeft:(id)uiOrName x:(CGFloat)x; -(UIView*)onLeft:(id)uiOrName x:(CGFloat)x y:(CGFloat)y; -(UIView*)onTop:(id)uiOrName y:(CGFloat)y; -(UIView*)onTop:(id)uiOrName y:(CGFloat)y x:(CGFloat)x; -(UIView *)onBottom:(id)uiOrName y:(CGFloat)y; -(UIView *)onBottom:(id)uiOrName y:(CGFloat)y x:(CGFloat)x; -(UIView*)relate:(XYLocation)location v:(CGFloat)value; -(UIView*)relate:(XYLocation)location v:(CGFloat)value v2:(CGFloat)value2; -(UIView*)relate:(XYLocation)location v:(CGFloat)value v2:(CGFloat)value2 v3:(CGFloat)value3; -(UIView*)relate:(XYLocation)location v:(CGFloat)value v2:(CGFloat)value2 v3:(CGFloat)value3 v4:(CGFloat)value4; -(UIView*)toCenter; -(UIView*)toCenter:(XYFlag)xyFlag;
這個很好理解的,基本讀過去就明白了,簡單易懂,其它的屬性,等後續文章用到再說。
Sagit 框架講解:事件
上一篇文章中,對事件有過一段講解:
框架對於UIView擴展了兩種點擊事件的綁定方式:
#pragma mark 擴展系統事件 -(UIView*)click:(NSString*)event; - (UIView*)addClick:(onClick)block;
click用於指定一個事件的名稱,addClick用於追加一個事件執行的代碼塊。
也說了事件的定址流程:
1:先找傳進來的event在所在的Controller中是否有對應的事件,若有,執行,若沒有繼續以下: 2:對event追加尾碼變成eventClick和eventClick:再看有沒有對應的事件,若有,執行,若沒有繼續以下: 3:對event追加尾碼變成EventController,看有沒有對應的控制器,若有,執行預設的open:事件跳轉,若沒有,則無綁定事件。
不過上面的佈局代碼中並沒使用click或addClick,同樣是觸發了這個流程:
核心就在於UIButtton的name,如果一個按鈕有name,則尋找事件,如果找到,就自動綁定事件。
因此,對於兩個name,Reg和Login:一路找到最終會找到RegController和LoginController,觸發STController中預先定義的open:事件。
Sagit 框架講解:keyValue屬性和[UINavigationBar globalSetting]
1:keyValue屬性
IT戀這裡有點特殊,跳轉後需要改變導航欄的返回圖標,原來在Controller中寫事件:
[self stPush:方法的第三個參數,指定一張圖片做為返回按鈕]
不過對於有代碼潔P的我,總想著怎麼消滅掉這些這些代碼,雖然兩個事件就幾行,但也不留。
這個參數怎麼傳到open:里呢?如果不是圖片,是指定文字為返回的按鈕呢?
最後想到一個相對完美的解決方案:
1:對UIView再擴展了一個keyValue的屬性,於是有了:
[[regBtn backgroundImage:@"login_btn"] keyValue:@{@"leftNavImage":@"nav_arrow_left_black"}];
2:open:事件中,再進行一下的簡單判斷拿值。
就這樣完美的解決了。
後來發現這個keyValue還有更多的用戶場景,如:設置控制導航欄的顯示或隱藏:
[self needNavigationBar:NO setNavBar:YES];//隱藏導航欄。
內部其實就是對keyValue進行取值或賦值:
-(UIView*)needNavigationBar:(BOOL)yesNo setNavBar:(BOOL)setNavBar { if(self.keyValue==nil) { self.keyValue=[NSMutableDictionary new]; } [self.keyValue set:@"needNavigationBar" value:yesNo?@"1":@"0"]; if(setNavBar && self.STController!=nil && self.STController.navigationController!=nil) { self.STController.navigationController.navigationBar.hidden=!yesNo; } return self; }
目前框架是自動控制導航欄的顯示或隱藏,不需要用戶去再操心的在每個頁面都是寫代碼了。
為了這個導航欄,真花我不少心力,特別是自定義返回和系統滑動返回,研究的過程都夠另外再寫一篇。
2:UINavigationBar globalSetting 的產生:
A:對於這個StartController這個頁面,有以下幾種情況會跳轉過來:
1:從歡迎引導頁WelcomeController進來; 2:用戶進行系統後,點擊退出時從SystemController進來; 3:當前用戶的Token數據失效,需要重新登陸時,從MainController中,跳進來;
不管從哪個地方過來,由於自身需要占根視圖,而為導航控制器,所以有一行代碼:
//從引導頁跳轉來時,需要將自身設置為導航根控制器 if(self.STController.navigationController==nil){[self.STController asRoot:RootViewNavigationType];}
框架對UIViewCtroller擴展了:asRoot方法,可以將當前Controller直接設置為根視圖:
//將當前視圖設置為根視圖 -(UIViewController*)asRoot:(RootViewControllerType)rootViewControllerType{ UIViewController *controller=self; if(rootViewControllerType==RootViewNavigationType) { controller = [[UINavigationController alloc]initWithRootViewController:self]; //self.navigationController.navigationBar.hidden=!self.view.needNavigationBar; } [UIApplication sharedApplication].delegate.window.rootViewController=controller; return self; }
B:導航欄進行統一的顏色風格處理(處理後,將對註冊、登陸、找回密碼等生效):
之前的代碼是這樣的:
框架封裝完成屬性無限連後可以這樣:
[[[[[[UINavigationBar globalSetting] barTintColor:ColorWhite]tintColor:ColorBlack] backgroundImage:nil] shadowImage:nil]
titleTextAttributes:@{NSForegroundColorAttributeName:ColorBlack}];
這裡有幾點坑和大伙分享:
坑A:如何進行屬性無限連
[UINavigationBar appearance] 這裡返回的是協議介面,並不是UINavigationBar實例
一開始看到UINavigationBar去接收appearance的屬性,聰明如我,就去擴展UINavigationBar的屬性方法,然後打算用無限連簡化。
結果一運行就死,進入坑裡徘徊了不少時間,最後才發現appearance返回的是UIAppearance介面,並不是UINavigationBar類型。
但是UIAppearnce又不能直接用,也不能對協議介面做擴展,一時蒙了下B。
然後繞到導航欄顯示不顯示、自定義返回和滑動返回,返回主界面沒主動往上頂等坑裡。
坑裡呆久出來後,想到另一種方式來實現無限連:
通過一個靜態方法返回一個自定義類,再由這個自定義類來連代碼,像這樣:
@implementation UINavigationBar (ST) +(UINavigationBarSetting*)globalSetting { return [UINavigationBarSetting new]; } @end @implementation UINavigationBarSetting #pragma mark 擴展系統屬性 -(UINavigationBarSetting*)tintColor:(id)colorOrHex { [UINavigationBar appearance].tintColor=[UIView toColor:(colorOrHex)]; return self; } -(UINavigationBarSetting*)barTintColor:(id)colorOrHex { [UINavigationBar appearance].barTintColor=[UIView toColor:(colorOrHex)]; return self; }
坑B:為何全局設置無效
以前的代碼,先執行ViewDidLoad里的全局設置,再執行asRoot,觸發導航欄,這樣是正常的:
-(void)viewWillAppear:(BOOL)animated { if(self.navigationController==nil) { [self asRoot:RootViewNavigationType]; //self.navigationController.navigationBar.hidden = YES; } }
但是這段代碼被我消滅了,其它地方的跳轉代碼都是直接,退出後轉跳:
改完後,發現全局失效了,最後坑裡呆了一圈才發現:
全局的設置,必須在導航欄UI出現之前設置才有效,所以,如果這樣寫代碼:
全局設置就不能寫在ViewDidLoad里了,必須寫在init中了。
總結:
1:用框架寫代碼很簡單,也很簡潔。
2:框架目前的代碼不多,早看早了結。
3:隨著應用場景的增多,框架會不斷的增強,預味著開發仍是很簡單,但要理解原理就需要花更多時間。
4:雖然教程是以IT戀為講解,但還是希望大伙多關心IT連,哈。