IOS開發(fā)中界面繪制占據(jù)了絕大部分的工作量,當(dāng)前可以使用StoryBoard酣栈,xib以及代碼三種方式定制所需要的界面惰说。在這三種方式中代碼是最靈活,最具有擴(kuò)展性的岳服,而特別是多人合作的大項目中StoryBoard剂公,xib不利于代碼合并。
接下來對之前項目的的界面開發(fā)做一些總結(jié)吊宋。
- UIViewController和重要子類
- UINavigationController
- UIView和重要子類
- UIControl
- UIScrollView
- 各種常用控件的注意點(后續(xù)介紹)
- 應(yīng)用約束Masonry庫(后續(xù)介紹)
- 常用的Code Snippet(后續(xù)介紹)
UIViewController和重要子類
UINavigationController
打交道最多的類無疑是這兩個诬留,一般我們采用UINavigationController(導(dǎo)航控制器,navi)作為UIViewController(vc)的容器贫母,最常用的方法是
//用指定的vc創(chuàng)建文兑,該vc位于棧底。
-(instancetype)initWithRootViewController:(UIViewController *)rootViewController;
//向棧里push一個vc腺劣,位于棧頂
-(void)pushViewController:(UIViewController *)viewController animated:(BOOL)animated;
//從棧里pop一個vc绿贞。
-(nullable UIViewController *)popViewControllerAnimated:(BOOL)animated;
一般app中只需要用到一個navi,在AppDelegate中完成初始化即可橘原,后續(xù)的界面遷移都是push和pop籍铁。值得注意的是使用了navi之后涡上,每個界面會產(chǎn)生一個navigationBar,即位于界面頂部的導(dǎo)航條拒名。導(dǎo)航條的作用是顯示當(dāng)前的界面title和返回按鈕吩愧,并支持自己添加需要的輔助功能。在任何vc中可以通過
self.navigationController.navigationBar
或者self.navigationItem
訪問這個組件增显,如設(shè)置背景色雁佳,添加按鈕等:
[self.navigationController.navigationBar setTitleTextAttributes:@{NSFontAttributeName : [UIFont systemFontOfSize:19], NSForegroundColorAttributeName : someColor}];
[self.navigationController.navigationBar setBackgroundColor:[UIColor whiteColor]];
UIBarButtonItem * activityDetail = [[UIBarButtonItem alloc] initWithTitle:@“幫助” style:UIBarButtonItemStylePlain target:self action:@selector(helpButtonClicked)];
self.navigationItem.rightBarButtonItem = activityDetail;
UIViewController
作為視圖控制器基類,我們一般在里面添加view代碼同云,顯示邏輯糖权,包括按鈕事件、代理方法(比如tableView的代理等)炸站。不注意的話vc會變得很大星澳,如果行數(shù)過多則不易維護(hù),所以說復(fù)雜的頁面應(yīng)該做架構(gòu)上的區(qū)分旱易,如MVVM模式將view禁偎,viewModel抽離出來。這里暫不細(xì)講阀坏。
vc最重要的方法包括:
生命周期相關(guān)的方法
//重寫該方法意味著不加載外部的xib文件届垫,自己繪制界面
-(void)loadView;
-(void)viewDidLoad;
-(void)viewWillAppear:(BOOL)animated;
-(void)viewDidAppear:(BOOL)animated;
以上方法在view加載過程中依次調(diào)用。一般在loadView或者viewDidLoad中添加自定義的view全释,但不能添加過于耗時的操作装处,以避免界面加載被阻塞導(dǎo)致的卡頓。一般把如網(wǎng)絡(luò)操作浸船,數(shù)據(jù)庫操作加載viewDidAppear中妄迁,界面加載可見之后執(zhí)行。
UIView和重要子類
UIView
先總結(jié)UIView的通用方法和屬性李命,然后介紹常用view控件的使用經(jīng)驗登淘。
初始化方法,以一個frame作為參數(shù)封字。
- (instancetype)initWithFrame:(CGRect)frame
基本
- userInteractionEnabled
默認(rèn)YES黔州,代表是否具有用戶可操作性,設(shè)為NO時任何手勢都不生效阔籽。在視圖重疊的時候流妻,用戶的觸摸會到達(dá)第一個開啟了userInteractionEnabled=YES的視圖。這個特性有兩種用法:穿透和攔截笆制,前者可以制作透明的不可交互背景绅这,后者可以做比如加載中這種遮罩。 - layer
UIView內(nèi)部實現(xiàn)在辆,類型是CALayer证薇,并封裝了許多未暴露到UIView中的內(nèi)容度苔,如cornerRadius屬性實現(xiàn)圓角只能調(diào)用view.layer.cornerRadius。 - tag
結(jié)合viewWithTag使用浑度,類似于android中的findViewById寇窑,類似于JavaScript中的getElementById的用法。但不是全局使用箩张,而是在一個view的子視圖中查找目標(biāo)tag甩骏。典型場景如兩個控件綁定了一個vc作為delegate,實現(xiàn)的協(xié)議中可以通過tag來判斷是來自哪個控件的事件伏钠。
位置與空間相關(guān):
- frame
- bounds
每個UIView有frame 和bounds兩個屬性,分別代表相對父容器的矩形和相對本容器的矩形(有點難理解)
struct CGRect {
CGPoint origin;
CGSize size;
};
bound一般用來修改view的相對位置谨设,類似于css中的相對布局熟掂,frame類似絕對布局。如圖
- center
中心點CGPoint - transform
視圖的仿射變換扎拣,默認(rèn)是CGAffineTransformIdentity赴肚,解釋為原始變換,意思就是維持原樣二蓝。通過修改這個值可以改變view的外觀誉券,尤其在動畫中常用。 - contentScaleFactor
縮放比例CGFloat - -sizeThatFits:
方法刊愚,返回適合其中子類的大小踊跟。
view的層次
- subviews
返回所有的子視圖 - superview
返回父視圖 - window
返回view的window對象 - -(void)removeFromSuperview;
把自己從父view中刪掉 - -(void)addSubview:(UIView *)view;
添加子view - -(void)bringSubviewToFront:(UIView *)view;
把子view拉到最前(重疊的情況下,默認(rèn)按照添加順序來一層層蓋住之前的view) - -(void)sendSubviewToBack:(UIView *)view;
把子view放到最后 - -(void)layoutSubviews;
override point. called by layoutIfNeeded automatically. As of iOS 6.0, when constraints-based layout is used鸥诽。該方法的調(diào)用時機(jī):
addSubview會觸發(fā)layoutSubviews
設(shè)置view的Frame會觸發(fā)layoutSubviews商玫,當(dāng)然前提是frame的值設(shè)置前后發(fā)生了變化
滾動一個UIScrollView會觸發(fā)layoutSubviews
旋轉(zhuǎn)Screen會觸發(fā)父UIView上的layoutSubviews事件 -改變一個UIView大小的時候也會觸發(fā)父UIView上的layoutSubviews事件
view的繪制
- (void)drawRect:(CGRect)rect;
由setNeedsDisplay來觸發(fā)調(diào)用,可以重寫該方法來實現(xiàn)一個自定義view牡借,例如在里面執(zhí)行
- (void)drawRect:(CGRect)rect {
// Drawing code.
//獲得處理的上下文
CGContextRef context = UIGraphicsGetCurrentContext();
//設(shè)置線條樣式
CGContextSetLineCap(context, kCGLineCapSquare);
//設(shè)置線條粗細(xì)寬度
CGContextSetLineWidth(context, 1.0);
//設(shè)置顏色
CGContextSetRGBStrokeColor(context, 1.0, 0.0, 0.0, 1.0);
//開始一個起始路徑
CGContextBeginPath(context);
//起始點設(shè)置為(0,0):注意這是上下文對應(yīng)區(qū)域中的相對坐標(biāo)拳昌,
CGContextMoveToPoint(context, 0, 0);
//設(shè)置下一個坐標(biāo)點
CGContextAddLineToPoint(context, 100, 100);
//設(shè)置下一個坐標(biāo)點
CGContextAddLineToPoint(context, 0, 150);
//設(shè)置下一個坐標(biāo)點
CGContextAddLineToPoint(context, 50, 180);
//連接上面定義的坐標(biāo)點
CGContextStrokePath(context);
}
調(diào)用時機(jī)drawRect是在Controller.loadView,viewDidLoad 兩方法之后掉用的.所以不用擔(dān)心在控制器中,這些View的drawRect就開始畫了.這樣可以在控制器中設(shè)置一些值給View(如果這些View draw的時候需要用到某些變量值).
- clipsToBounds
默認(rèn)NO,代表子元素顯示時可以超出該view的邊界钠龙。 - backgroundColor
背景顏色 - alpha
透明度炬藤,默認(rèn)為1.0代表不透明,注意當(dāng)alpha為0時等同于hidden碴里,控件無法接收到點擊事件沈矿。注意該值會影響子視圖的繪制,但子視圖的alpha不受影響咬腋,子視圖繪制時的alpha實際效果等于包含鏈上的所有alpha之乘積细睡。 - opaque
不透明,默認(rèn)為YES - hidden
隱藏帝火,默認(rèn)為NO - contentMode
參考UIViewContentMode溜徙,有多重展示的模式湃缎,如圖:
動畫相關(guān)
- +(void)animateWithDuration:(NSTimeInterval)duration delay:(NSTimeInterval)delay options:(UIViewAnimationOptions)options animations:(void (^ )(void))animations completion:(void (^ __nullable)(BOOL finished))completion
方法接受幾個參數(shù):duration, delay, options, animations, completion。duration代表執(zhí)行多久delay代表延遲多少時間開始執(zhí)行蠢壹,option參考UIViewAnimationOptions(篇幅過大此處略過)嗓违,animation和completion各為一個block,代表執(zhí)行的動畫和完成后執(zhí)行的代碼图贸。一段示例代碼(慢慢放大后迅速縮小的提示效果):
其他方法和該方法類似蹂季,實際使用時根據(jù)實際情況決定。
手勢相關(guān)
添加和刪除手勢疏日,不過多介紹偿洁。
- -(void)addGestureRecognizer:(UIGestureRecognizer*)gestureRecognizer;
- -(void)removeGestureRecognizer:(UIGestureRecognizer*)gestureRecognizer;
UIControl
子類包括:
其中UIButton和UITextField,UISwitch都是平時十分常用的控件沟优,作為他們的基類有必要介紹一下涕滋。
重要的屬性與方法:
- enabled
是否激活,默認(rèn)YES挠阁,設(shè)為NO在視覺上會變?yōu)榛疑?/li> - selected
是否選中宾肺,默認(rèn)NO,參考UIControlState - highlighted
是否highlighted侵俗,默認(rèn)NO锨用,參考UIControlState - state
UIControlState類型
UIControl 基本的 State 變化過程如下
1.什么都沒干的時候:Normal
2.當(dāng)你的手指按下去,還沒放的時候:Highlighted
3.當(dāng)手指放開的時候:如果這個 UIControl 有 Selected 狀態(tài)的話隘谣,就會變成: Selected
再重復(fù)上述過程一次增拥,就會從 Selected->Highlighted-> Normal
但是普通的 UIButton 這個 UIControl 的 subclass,是沒有 Selected 狀態(tài)的寻歧,它就只有 Normal 和 Highlighted跪者,只會在這兩個狀態(tài)間切換。(正常情況下熄求,如果你設(shè)置了 disable 的話渣玲,還會變到 Disabled)
按鈕事件
- (void)addTarget:(nullable id)target action:(SEL)action forControlEvents:(UIControlEvents)controlEvents;
普通的按鈕通過該方法綁定事件即可,其中sel是一個方法指針弟晚,UIControlEvents定義了可發(fā)送事件的幾種類型忘衍。按鈕點擊一般使用UIControlEventTouchUpInside。代表在控件范圍內(nèi)按下去并放開卿城。其余的屬性可參考UIControlEvents枚钓。
自定義事件實現(xiàn)
- (BOOL)beginTrackingWithTouch:(UITouch *)touch withEvent:(nullable UIEvent *)event;
- (BOOL)continueTrackingWithTouch:(UITouch *)touch withEvent:(nullable UIEvent *)event;
- (void)endTrackingWithTouch:(nullable UITouch *)touch withEvent:(nullable UIEvent *)event;
通過以上三個方法可以實現(xiàn)自定義的控件,比如要自己實現(xiàn)滑塊效果瑟押,先調(diào)用begin搀捷,然后在continue中利用touch.locationInView的值來改變滑塊代表的數(shù)值,在end中完成網(wǎng)絡(luò),數(shù)據(jù)庫等操作嫩舟。