iOS開發入門第4節:純代碼寫UI

上一節中,我們用簡簡單單的幾行代碼實現了一個iOS動畫,本節將對iOS動畫代碼做詳細解釋,並開始用純代碼方式來進行UI開發。

什麼是UI開發:UI即User Interface(用戶界面)的簡稱,泛指用戶的操作界面。通俗點說,就是一個APP上用戶能看到的、能觸摸、拖拉的東西,比如背景、文字、按鈕、圖片等都是構成UI的元素,選用什麼顏色、什麼形狀、擺放到什麼位置都是UI設計的工作。UI設計可以讓軟件變得美觀有個性有品味,還可讓軟件的操作變得舒適、簡單、自由,充分體現軟件的定位和特點。因此UI設計是很重要的,但是UI設計主要是設計師和美工的工作。程序員的主要工作是在App上實現這些UI設計,我們稱為UI開發。UI設計與開發直接影響用戶的體驗,在移動App開發中佔有很重的比例,每一個iOS程序員都必須熟練掌握。本節分享一種UI開發方法:用純代碼來寫UI。

一、創建工程

打開Xcode創建一個iOS的"Single View App"工程,工程名為:MyCode。不懂創建的人請參看

iOS開發入門第4節:純代碼寫UI

二、工程目錄簡介

上圖界面中左側有四個大文件夾,下面大致瞭解一下這些文件夾的作用:

1. Products: 主要用於mac電腦軟件開發,iOS開發用不到。

2. MyCodeTests: 用於單元測試。

3. MyCodeUITests: 用於UI測試。

4. MyCode: iOS開發的內容主要都是存放在這個文件夾中。

MyCode這個文件夾又包含:

4.1 AppDelegate.swift:代表應用程序,App初始化需要的內容都在這裡做,App是從這裡開始啟動的,這個文件暫時不做深入。

4.2 ViewController.swift: 這是iOS存放視圖控制器類的文件(如果不懂得什麼是“類”,應該先看看“面向對象”編程思想相關的文章),裡面定義一個頁面 (ViewController),我們編寫的UI代碼都要寫在這個頁面裡,比如文字、按鈕、圖片等元素都要擺放在這個頁面裡,才能展示給用戶看。本節將重點關注這個文件以及裡面定義的類。

4.3 Main.storyboard: 這個文件裡面定義一個主storyboard(即故事板),storyboard裡面可以放置多個頁面(ViewController),頁面之間的跳轉關係也可以在storyboard裡面定義。故事板可以幫助我們用比較直觀的方式來快速的開發UI,通過storyboard我們可以看到我們設計的頁面長什麼樣子。比如,我們要在頁面上添加一張圖片,我們只要將一個圖片控件直接拉到storyboard上,就可以看到這個圖片在頁面上到底是大是小,位置在哪裡等等。這是iOS推薦的UI開發模式。有人要問了,那我們還要用代碼寫UI,不是很麻煩嗎?其實這兩種方式寫UI各有優缺點,我們可以取長補短,這在後面講到storyboard的時候再討論。Main.storyboard顧名思義就是主頁面所在的storyboard,也就是點開App後,默認的用戶看到的第一個頁面。我們可以在一個項目中定義多個storyboard,一個storyboard裡面又可以定義多個頁面(ViewController)。所以storyboard可以認為是一群相關頁面的集合。

5. Assets.xcassets: 這個文件夾主要用於存放資源文件,比如圖片

6. LauchScreen.storyboard: 顧名思義就是啟動頁面所在的storyboard文件。在打開一個App的時候,一般不會直接跳到主頁面,經常會先來個倒計時,先顯示某某公司Logo或者廣告圖片視頻什麼的,承擔這個功能的頁面就叫啟動頁。

7. info.plist: 這個文件是項目的配置文件,比如主頁面是哪個頁面,Main.storyborad只是創建項目時系統默認的主頁面所在的storyborad,在info.plist裡可以隨時更換到別的storyborad。

三、認識視圖控制器

下面我們重點關注ViewController.swift這個文件,單擊這個文件,得到如下界面(紅框和箭頭是我做的標記),下面逐一解釋代碼的作用

iOS開發入門第4節:純代碼寫UI

import UIKit:UIKit是iOS的SDK提供給我們專門用於編寫UI的庫或者包,import是導入這個庫的意思,只有import之後,在這個文件中才能使用這個庫提供的相關的類來編寫UI。以後還會用到更多SDK中的庫,也要這麼導入。上面說的這些庫都是iOS的SDK內部提供的庫,使用時可以直接這樣導入。站在巨人的肩膀上,明顯可以省很多事,因此有時我們要經常在項目中用別人造過的輪子或者說工具,這些叫第三方庫。使用第三方庫時略微麻煩一點,怎麼操作請關注後續我的文章。

UIViewController:這是UIKit庫中一個重要的類,顧名思義“視圖控制器”。項目創建時,系統自動為我們創建了一個ViewController類來繼承UIViewController類。一個ViewController類的實例化對象對應App中的一個頁面。所以很明顯,我們的UI代碼應該寫在ViewController類裡面。我們暫時不用關注這個類是怎麼被實例化的,只要知道當我們編譯運行時,系統會自動為我們實例化這個類。

viewDidLoad(): 這是UIViewController中的一個“方法”(也叫“函數”),代表頁面容器已經初始化完畢,這時頁面什麼都沒有還是空白的,我們可以在這時往頁面中添加我們設計的UI元素,比如圖片、文字。每個頁面都有一個完整的生命週期:從它開始被創建一直到它被銷燬回收。在這整個生命週期的不同階段,UIViewController都會提供對應的函數(viewDidLoad()就是其中一個),讓我們有機會進行修改界面、回收資源等操作。我們要添加的UI代碼都是寫在圖中紅色箭頭所指的地方。其他生命週期函數還有很多,有興趣可以自己查找學習,在這裡不做介紹。

四、UIView

UIView是UIKit庫中視圖的基類,可以理解為頁面中的一個色塊,如下圖大紅框框中的部分就是一個頁面(ViewController),而其中的紅色的塊就是一個UIView。

iOS開發入門第4節:純代碼寫UI

1. 屬性和佈局

我們對視圖最關心的有兩點:

a) 它長什麼樣:這稱為視圖的屬性,比如是什麼顏色、是否有邊框、邊框的顏色、邊框的大小等

b) 它應該放在頁面的哪個位置:這就是佈局,佈局有兩種方法。一種使用frame,另一種是用AutoLayout。

(1)屬性

對於以後要用到的其他更高級的視圖控件,比如UILabel(專門顯示文字)、UIImageView(專門顯示圖片)、UIButton(按鈕)等都是類似的。只是他們有更多的屬性而已。我們學習這些視圖,無非就是熟悉他們的屬性和佈局,因此可以舉一反三。

下面是一段最簡單的例子:

let purpleView = UIView()

purpleView.backgroundColor=UIColor.purple

purpleView.frame=CGRect(x: 0, y: 100, width: 150, height: 150)

view.addSubview(purpleView)

可以將上面這段黑色加粗的代碼拷貝到如下圖所示的位置:

iOS開發入門第4節:純代碼寫UI

編譯運行效果如下圖:

iOS開發入門第4節:純代碼寫UI

下面對代碼逐行做說明:

let purpleView = UIView() //這句是創建一個視圖,注意要定義在函數外面

purpleView.backgroundColor = UIColor.purple //這句是將視圖的背景色設置為紫色

purpleView.frame = CGRect(x: 0, y: 100, width: 150, height: 150) /*這句是設置視圖的大小和位置:x:0表示視圖與頁面的左邊距離為0,y:100表示視圖與頁面的上邊距離為100,width:150代表視圖寬度為150,height:150代表視圖的高度為150。*/

view.addSubview(purpleView) //這句是表示將purpleView這個視圖對象添加到頁面裡

注意:iOS用“//”來註釋單行代碼,可以用這個方法將臨時不用的代碼註釋起來,也可以用來對代碼進行說明。被“//”註釋後的代碼在程序運行時,將不會執行。

(2)佈局

還可以用自動佈局AutoLayout的約束方式來限制視圖的位置:

//創建一個視圖,與上面一樣要放置的函數外面

let redView = UIView()

//禁止將AutoresizingMask轉化為Constraints

redView.translatesAutoresizingMaskIntoConstraints = false

// 背景色為紅色

redView.backgroundColor = UIColor.red

// 將視圖添加到頁面中

view.addSubview(redView)

//創建約束,注意:要在視圖添加到其父容器後,才能進行約束設置,否則App會奔潰

//寬度約束

let widthConstraint = NSLayoutConstraint(item: redView, attribute: .width, relatedBy: .equal, toItem: nil, attribute: .notAnAttribute, multiplier: 0, constant: 150)

//高度約束

let heightConstraint = NSLayoutConstraint(item: redView, attribute: .height, relatedBy: .equal, toItem: nil, attribute: .notAnAttribute, multiplier: 0, constant: 150)

//頂部約束

let topConstraint = NSLayoutConstraint(item: redView, attribute: .top, relatedBy: .equal, toItem: view, attribute: .top, multiplier: 1.0, constant: 100)

//左側約束

let leftConstraint = NSLayoutConstraint(item: redView, attribute: .left, relatedBy: .equal, toItem: view, attribute: .left, multiplier: 1.0, constant: 150)

//在頁面中添加多個約束

view.addConstraints([widthConstraint,heightConstraint,leftConstraint,topConstraint])

上面這段黑色加粗的代碼可以直接拷貝到項目中:

iOS開發入門第4節:純代碼寫UI

編譯運行結果如下:

iOS開發入門第4節:純代碼寫UI

用自動佈局AutoLayout的約束來設置視圖的位置是比較靈活的,但是iOS系統提供的這種寫法,明顯太繁瑣。所以一般使用第三方提供的SnapKit庫來簡化代碼的寫法,有興趣的人可以查閱相關資料。

2. 動畫

上面談到的屬性和佈局都是設置靜止不動的內容,有時我們想讓這些圖片或文字能夠動起來,這樣看起來比較生動有趣,這就要用到動畫。

在 那節,我們分享了一個簡單的iOS動畫,沒有對代碼做任何解釋,下面將對動畫代碼做詳細說明。主要代碼如下:

animView.frame=CGRect(x:0,y:0,width:100,height:100) //設置動畫視圖的尺寸

animView.center=view.center //動畫視圖放在父視圖的正中央

animView.backgroundColor=UIColor.green//動畫視圖的背景色設置為綠色

view.addSubview(animView)//將動畫視圖添加到父視圖(即頁面)

UIView.animate(withDuration: 2,delay:1,usingSpringWithDamping:0.2,initialSpringVelocity:0,options:[.repeat,.autoreverse], animations:{

self.animView.transform=CGAffineTransform(scaleX: 0.5, y: 0.5)//將動畫視圖大小縮小為原來的一半

},completion:nil)

前面四行,是設置屬性和佈局可以參看上面的,不做說明。我們重點關注最後一個方法:

UIView.animate()這個方法是UIView類提供的一個靜態方法,專門用於播放和控制視圖動畫。裡面的參數有:

withDuration: 2表示動畫總的時長為2秒

delay:1表示動畫延時1秒才開始播放,就是這段動畫代碼被執行後不馬上播放,而要等1秒鐘後才開始播放。

usingSpringWithDamping:0.2彈簧動畫的阻尼值,也就是相當於摩擦力的大小,該屬性的值從0.0到1.0之間,越靠近0,阻尼越小,彈動的幅度越大,反之阻尼越大,彈動的幅度越小,如果大道一定程度,會出現彈不動的情況。

initialSpringVelocity:0彈簧動畫的速率,或者說是動力。值越小彈簧的動力越小,彈簧拉伸的幅度越小,反之動力越大,彈簧拉伸的幅度越大。這裡需要注意的是,如果設置為0,表示忽略該屬性,由動畫持續時間和阻尼計算動畫的效果。

options後面可以設置很多可選項,.repeat這個選項表示動畫是重複的,.autoreverse這個選項表示動畫播放完畢後會自動倒播,注意這些選項前面要加一個點。

animations:{}這個大括號裡面我們要指定視圖最終屬性值。比如我們要讓一個原來透明度為1的視圖慢慢變為透明度為0.5,這個過程我們不需要關心,我們只要在這個大括號中將視圖最終0.5這個值設置好就行了。系統會根據視圖最初的透明度以及我們設置的這個0.5自動生成中間值並用這些值來控制完成動畫過程。也就是說,我們代碼只要告訴系統,視圖最終的屬性值是多少系統就會為我們自動生成這些動畫過程。

scanX:0.5,y:0.5表示這是一個縮放動畫,並且視圖在X方向縮小為原來的一半,Y方向也縮小為原來的一半,總體看就是方塊整體慢慢縮小一半。

2.1 動畫類型

按照動作,動畫可分為以下幾個類型:

(1)平移:

self.animView.transform=CGAffineTransform(translationX: -200, y: 20)

translationX: -200, y: 0表示視圖向左移動200距離,同時向下移動20距離。x正值表示向右移動,負值表示向左移動;y正值表示向下移動,負值表示向上移動。

(2)縮放:

self.animView.transform=CGAffineTransform(scaleX: 0.5, y: 0.5)

scanX:0.5,y:0.5表示視圖在x方向縮小為原來的一半,y方向也縮小為原來的一半,總體看就是方塊整體慢慢縮小一半。x和y的值一般要大於等於0

(3)旋轉:

self.animView.transform=CGAffineTransform(rotationAngle:CGFloat.pi/4)

rotaionAngle:CGFloat.pi/4表示順時針旋轉45度,CGFloat.pi/4代表旋轉的角度。

2.1 組合動畫

有的人說了:我想同時變可以嗎,比如平移的同時縮放?當然可以啦。可以這樣寫:

let scale=CGAffineTransform(scaleX:0.6,y:0.6)//縮小到原來的0.6倍

let rotation=CGAffineTransform(rotationAngle:CGFloat.pi/4)//順時針旋轉45度

self.animView.transform=rotation.concatenating(scale)

用concatenating()這個方法,你想套幾個動畫都可以,比如還有一個平移動畫可以這樣寫:

let transY=CGAffineTransform(translationX: 0, y: 150)//向下移動150的距離

let scale=CGAffineTransform(scaleX:0.6,y:0.6)//縮小到原來的0.6倍

let rotation=CGAffineTransform(rotationAngle:CGFloat.pi/4)//順時針旋轉45度

self.animView.transform=transY.concatenating(rotation.concatenating(scale))

這些動畫就不在這裡演示了,因為這裡沒辦法加視頻。用相關代碼替換掉對應的行就可以實現。

本系列會不斷更新,有興趣的同學,請關注我。


分享到:


相關文章: