目前swiftUI最低支持iOS13,蘋果還在不斷升級(jí)完善,目前還不成熟,因?yàn)楝F(xiàn)在widget必須用swiftUI布局,所以有幸把swiftUI應(yīng)用到項(xiàng)目。當(dāng)我寫swiftUI的demo時(shí)感覺這東西好簡(jiǎn)單EZ,但是真到了項(xiàng)目中是各種坑
編輯代碼的兩種方式
1.代碼
2.preview畫布,拖拽控件,檢查器,inspector
因?yàn)閜review有時(shí)有問題,也不方便調(diào)試,需要維護(hù)一套假數(shù)據(jù),所以一般用代碼。
布局
swiftUI控件大多為結(jié)構(gòu)體
基本布局需要三個(gè)Stack:
HStack:水平布局,X軸
VStack:垂直布局,Y軸
ZStack:層疊布局,Z軸
可以看做是一個(gè)三維坐標(biāo)系
如果原來寫過flutter會(huì)對(duì)這個(gè)布局很熟悉,HStack相當(dāng)于Row,VStack相當(dāng)于Colum,但是swiftUI,HStack的alignment只有垂直對(duì)齊方式,VStack的alignment只有水平對(duì)齊方式,對(duì)齊方式是指Stack內(nèi)部元素的對(duì)齊方式,而不是Stack本身,Stack的實(shí)際大小是根據(jù)里面子視圖的大小來撐開的,如果Stack內(nèi)部只有一個(gè)元素,不管你設(shè)置任何對(duì)齊方式都是不起作用的
比如有一個(gè)需求,設(shè)置一個(gè)圖片緊貼左上角
EZ啊
VStack(alignment: .leading){
Image("cloudy")
}
發(fā)現(xiàn)是居中,然后修改
ZStack(alignment:.topLeading){
Image("cloudy")
}
還是居中沒變,是因?yàn)镾tack內(nèi)部就一張圖片,所以Stack就是圖片大小,需要撐開Stack才能設(shè)置內(nèi)部坐上對(duì)齊,修改如下
ZStack(alignment:.topLeading){
Color(.clear)
Image("cloudy")
}
用Color來撐開Stack,當(dāng)然也可以用別的方式,比如
VStack(alignment: .leading){
HStack(alignment: .top){
Image("cloudy")
Spacer()
}
Spacer()
}
用Spacer()撐開Stack
通過這三種Stack互相嵌套可以實(shí)現(xiàn)各種復(fù)雜的布局
需要注意的是;這三種Stack中的控件之間默認(rèn)是有間距的,所以需要指定間距,比如VStack(spacing:0)
布局通用屬性
細(xì)節(jié)的位置變化需要用到frame,offSet,position,padding,layoutPriority
frame只能指定寬高
.frame(minWidth: ,maxWidth: , minHeight: ,maxHeight:)用來給調(diào)用者一個(gè)大小限制,不能超出這個(gè)限制
idealWidth: ,idealHeight: 理想大小。必須配合.fixedSize(horizontal: true, vertical: false)才能生效,例如:
.frame(idealWidth: 300)
.fixedSize(horizontal: true, vertical: false)//設(shè)置在哪個(gè)方向強(qiáng)制生效,水平方向還是垂直方向
min寬高,類似于UIKit自動(dòng)布局的>=
max寬高,類似于UIKit自動(dòng)布局的<=
offSet:在視圖應(yīng)有的位置加上偏移量
position:在上層容器強(qiáng)制定位,相當(dāng)于UIKit里的frame(x,y),但是這里的x,y指的是視圖中心點(diǎn)的位置
padding:內(nèi)邊距
.padding(20)內(nèi)邊距都為20
.padding(.leading,20)左側(cè)內(nèi)邊距為20
.padding([.top, .leading],20)左側(cè)上側(cè)內(nèi)邊距為20
layoutPriority(0):視圖優(yōu)先級(jí),默認(rèn)為0
Space()撐開子控件到父控件的最大長度,經(jīng)常用,比如在屏幕最左邊和最右側(cè)顯示兩個(gè)文字對(duì)齊
HStack{
Text("n")
Spacer()
Text("w")
}
獲取上層視圖空間大小,這個(gè)很常用
GeometryReader{proxy in
Text(String(describing: proxy.size))
}
常用控件
視圖分為:
緊湊視圖:大多數(shù)控件屬于這一類型,控件中的內(nèi)容決定控件的實(shí)際大小
貪婪視圖:Circel,Spacer,Color等,控件在父視圖范圍內(nèi)會(huì)盡可能多的去鋪滿剩余空間
一般有內(nèi)容的視圖是緊湊類型,容器類視圖為貪婪類視圖
Text
.truncationMode(.middle)//設(shè)置超出文本的省略方式
.lineLimit(1)//默認(rèn)不限制行數(shù)
.font(.system(size: 85))//字體過大,超過顯示區(qū)域會(huì)整體消失,不顯示
Image:
如果圖片大小和顯示大小不一樣,需要手動(dòng)設(shè)置圖片的大小,需要先設(shè)置.resizable(),否則frame寬高不生效
Image("forecast_icon_clound")
.resizable()
.frame(width: 22, height: 22)
.fixedSize(horizontal: true, vertical: true)//這句可以不加
.aspectRatio(contentMode: .fill)
Button,Picker,Slider,WebView,TextField,ScrollView這些用法和UIKit相似,只是把UI前綴去了
List類似于TableView
GridView:有LazyHGrid,LazyVGrid,相當(dāng)于collectionView
let gridItem = [GridItem(.flexible(),spacing: 0)]
LazyHGrid(rows: gridItem, spacing:0) {
ForEach(0...10,id:\.self) { index in
setUpCell()
}
}
Group把控件裝到這個(gè)組里面,可以進(jìn)行一些統(tǒng)一配置
Path劃線,折線虛線都可以,舉一個(gè)虛線的例子:
Path{ path in
path.move(to: CGPoint(x: 0, y: 100))
path.addLine(to: CGPoint(x: 200, y: 100))
}
.stroke(Color(white: 1, opacity: 0.2),style: StrokeStyle(lineWidth: 1, lineCap: .round, lineJoin:.round, dash: [1,2], dashPhase: 0))
屬性裝飾器
理解 SwiftUI 里的屬性裝飾器
@State 屬性變化,刷新UI。用于一個(gè)對(duì)象內(nèi)屬性修飾
@StateObject 用于生成和管理狀態(tài)屬性的生命周期
@ObservedObject 修飾共享狀態(tài)從外部傳遞進(jìn)來的屬性,修飾的屬性要實(shí)現(xiàn)ObservableObject協(xié)議
ObservableObject協(xié)議,對(duì)應(yīng)屬性內(nèi)要實(shí)現(xiàn)
var age = 100 {
willSet {
objectWillChange.send()
}
}
簡(jiǎn)寫是用@Published修飾@Published var age = 100
需要注意的是多層監(jiān)聽屬性傳遞都要用@ObservedObject修飾,所以有了@EnvironmentObject
@EnvironmentObject 修飾全局,避免多個(gè)對(duì)象傳遞用@ObservedObject修飾
ParentView()
.environmentObject(user)
struct ParentView : View{
var body: some View {
ChindView()
}
}
struct ChindView : View {
@EnvironmentObject var user : UserModel
}
@Binding 修飾的屬性變?yōu)橐脗鬟f