【View層】IOS純代碼繪制界面(一)

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類似絕對布局。如圖

Paste_Image.png
  • 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溜徙,有多重展示的模式湃缎,如圖:
Paste_Image.png

動畫相關(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í)行的代碼图贸。一段示例代碼(慢慢放大后迅速縮小的提示效果):

Paste_Image.png

其他方法和該方法類似蹂季,實際使用時根據(jù)實際情況決定。

手勢相關(guān)
添加和刪除手勢疏日,不過多介紹偿洁。

  • -(void)addGestureRecognizer:(UIGestureRecognizer*)gestureRecognizer;
  • -(void)removeGestureRecognizer:(UIGestureRecognizer*)gestureRecognizer;
UIControl

子類包括:


Paste_Image.png

其中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ù)庫等操作嫩舟。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末氢烘,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子家厌,更是在濱河造成了極大的恐慌播玖,老刑警劉巖,帶你破解...
    沈念sama閱讀 217,509評論 6 504
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件饭于,死亡現(xiàn)場離奇詭異蜀踏,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)掰吕,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,806評論 3 394
  • 文/潘曉璐 我一進(jìn)店門果覆,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人殖熟,你說我怎么就攤上這事局待。” “怎么了吗讶?”我有些...
    開封第一講書人閱讀 163,875評論 0 354
  • 文/不壞的土叔 我叫張陵燎猛,是天一觀的道長恋捆。 經(jīng)常有香客問我照皆,道長,這世上最難降的妖魔是什么沸停? 我笑而不...
    開封第一講書人閱讀 58,441評論 1 293
  • 正文 為了忘掉前任膜毁,我火速辦了婚禮,結(jié)果婚禮上愤钾,老公的妹妹穿的比我還像新娘瘟滨。我一直安慰自己,他們只是感情好能颁,可當(dāng)我...
    茶點故事閱讀 67,488評論 6 392
  • 文/花漫 我一把揭開白布杂瘸。 她就那樣靜靜地躺著,像睡著了一般伙菊。 火紅的嫁衣襯著肌膚如雪败玉。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,365評論 1 302
  • 那天镜硕,我揣著相機(jī)與錄音运翼,去河邊找鬼。 笑死兴枯,一個胖子當(dāng)著我的面吹牛血淌,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播财剖,決...
    沈念sama閱讀 40,190評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼悠夯,長吁一口氣:“原來是場噩夢啊……” “哼癌淮!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起疗疟,我...
    開封第一講書人閱讀 39,062評論 0 276
  • 序言:老撾萬榮一對情侶失蹤该默,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后策彤,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體栓袖,經(jīng)...
    沈念sama閱讀 45,500評論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,706評論 3 335
  • 正文 我和宋清朗相戀三年店诗,在試婚紗的時候發(fā)現(xiàn)自己被綠了裹刮。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 39,834評論 1 347
  • 序言:一個原本活蹦亂跳的男人離奇死亡庞瘸,死狀恐怖捧弃,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情擦囊,我是刑警寧澤违霞,帶...
    沈念sama閱讀 35,559評論 5 345
  • 正文 年R本政府宣布,位于F島的核電站瞬场,受9級特大地震影響买鸽,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜贯被,卻給世界環(huán)境...
    茶點故事閱讀 41,167評論 3 328
  • 文/蒙蒙 一眼五、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧彤灶,春花似錦看幼、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,779評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至搏熄,卻和暖如春棚唆,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背搬卒。 一陣腳步聲響...
    開封第一講書人閱讀 32,912評論 1 269
  • 我被黑心中介騙來泰國打工瑟俭, 沒想到剛下飛機(jī)就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人契邀。 一個月前我還...
    沈念sama閱讀 47,958評論 2 370
  • 正文 我出身青樓摆寄,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子微饥,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 44,779評論 2 354

推薦閱讀更多精彩內(nèi)容