一:编写第一个SwiftUI程序
1,创立SwiftUI工程
-左面是代码区
-右侧是Canvas
编写代码时,右侧的Canvas可以实时显示出代码的UI预览效果
2,编写UI布局代码
经过拖拽添加UI控件
VStack:SwiftUI常用的一种布局元素,可以用来垂直地叠加视图
HStack:水平叠加视图
HStack {
VStack {
Text("Rooms")
Text("20 people")
}
}
在文字左面添加一个图片
HStack {
// `photo`是体系自带资源库中的图片
Image(systemName: "photo")
VStack {
Text("Rooms")
Text("20 people")
}
}
在Canvas中将VStack修正为左对齐
设置Text的字号
HStack {
Image(systemName: "photo")
VStack(alignment: .leading) {
Text("Rooms")
Text("20 people")
.font(.subheadline)
}
}
咱们称.font(.subheadline)为润饰器(modifier),用来自界说视图的外观或行为
设置Text的色彩为secondary
HStack {
Image(systemName: "photo")
VStack(alignment: .leading) {
Text("Rooms")
Text("20 people")
.font(.subheadline)
.foregroundColor(.secondary)
}
}
将HStack替换为List
3,设置数据源
添加Room模型
在SwiftUI中,需要让模型遵照Identifiable协议,完结id特征
在ContentView中运用Room数据来展现UI
4,丰富UI内容
设置图片圆角
经过拖拽Modifier库来完结
设置Navigation、NavigationTitle以及给每个单元格设置跳转
NavigationView {
List(rooms) { room in
NavigationLink(destination: Text(room.name)) {
Image(systemName: "photo")
.cornerRadius(8.0)
VStack(alignment: .leading) {
Text(room.name)
Text("(room.capacity) people")
.font(.subheadline)
.foregroundColor(.secondary)
}
}
}
.navigationTitle(Text("Rooms"))
}
进入实时方法,查看效果
将子视图提成一个单独的视图
创立新的页面:RoomDetail
struct RoomDetail: View {
let room: Room
var body: some View {
Image(room.imageName)
.resizable()
.aspectRatio(contentMode: .fit)
}
}
struct RoomDetail_Previews: PreviewProvider {
static var previews: some View {
RoomDetail(room: testData[0])
}
}
设置navigationBarTitle
Image(room.imageName)
.resizable()
.aspectRatio(contentMode: .fit)
.navigationBarTitle(Text(room.name))
在预览中添加NavigationView上下文
struct RoomDetail_Previews: PreviewProvider {
static var previews: some View {
NavigationView {
RoomDetail(room: testData[0])
}
}
}
调整navigationBarTitle的展现方法
将RoomCell的跳转修正为前往RoomDetail页面
struct RoomCell: View {
let room: Room
var body: some View {
NavigationLink(destination: RoomDetail(room: room)) {
//
}
}
}
二:Swift UI的工作方法
2.1 View
A View Defines a Piece of UI
在SwiftUI中,视图是一种遵守View协议的结构,而不是继承自根底类的类
A View Defines its Dependencies
2.2 状态特征
@State
当SwiftUI看到一个带@State状态变量的视图时,它会以视图的名义为那个变量分配存储空间。
绿色部分是APP的内存
紫色是SwiftUI所处理的内存
SwiftUI可以观察到@State变量合时被读写,一同SwiftUI知道zoom是从body中读取的,SwiftUI会在@State变量产生更改时,使用新的状态值,改写烘托。
例:完结在RoomDetail中,点击图片修正填充方法
struct RoomDetail: View {
let room: Room
@State private var zoomed = false
var body: some View {
Image(room.imageName)
.resizable()
.aspectRatio(contentMode: zoomed ? .fit : .fill) // 根据zoomed值修正填充方法
.navigationBarTitle(Text(room.name), displayMode: .inline)
.onTapGesture {
self.zoomed.toggle() // 点击修正zoomed的值
}
}
}
2.3 实际来历
在SwiftUI中,UI或许因不同的数据,处于不同的状态,咱们将这些用来绘制UI的数据称为“实际来历”,“实际来历“由状态变量和模型一同组成。
特征可以简略地分为:实际来历(Source of Truth)和衍生值(Derived Value)
zoomed变量是一个实际来历,contentMode衍生自它,当体系观察到zoomed变量产生变化时,SwiftUI结构会请求新的body,改写烘托,从头生成一个新的宽高比视图,接下来覆盖contentMode。
数据流原语(Data Flow Primitives)
SwiftUI是数据驱动,而不是事情驱动
三:完善Rooms APP
添加动画
.onTapGesture {
withAnimation {
self.zoomed.toggle()
}
}
添加一个ZStack
ZStack(alignment: .topLeading) {
Image(room.imageName)
.resizable()
.aspectRatio(contentMode: zoomed ? .fit : .fill)
.navigationBarTitle(Text(room.name), displayMode: .inline)
.onTapGesture {
withAnimation {
self.zoomed.toggle()
}
}
Image(systemName: "video.fill")
.font(.title)
.padding(.all)
}
固定图标的方位
Image(room.imageName)
.frame(minWidth:0, maxWidth: .infinity, minHeight: 0, maxHeight: .infinity)
一同预览多个View
struct RoomDetail_Previews: PreviewProvider {
static var previews: some View {
Group {
NavigationView {
RoomDetail(room: testData[0])
}
NavigationView {
RoomDetail(room: testData[1])
}
}
}
}
添加动效
给视频图标添加过渡动效
if room.hasVideo && !zoomed {
Image(systemName: "video.fill")
.font(.title)
.padding(.all)
.transition(.move(edge: .leading))
}
给图片的动效延伸时刻
.onTapGesture {
withAnimation(.easeInOut(duration: 2)) {
self.zoomed.toggle()
}
}
支撑动态添加
监测数据模型的改动,实时更新UI
创立RoomStore储存Room模型
import SwiftUI
class RoomStore {
var rooms: [Room]
init(rooms: [Room] = []) {
self.rooms = rooms
}
}
遵守ObservableObject协议
class RoomStore: ObservableObject {
@Published var rooms: [Room]
//
}
声明EnvironmentObject类型变量
@EnvironmentObject var store: RoomStore
传入EnvironmentObject类型变量
struct ContentView_Previews: PreviewProvider {
static var previews: some View {
ContentView()
.environmentObject(RoomStore(rooms: testData))
}
}
列表中添加一个按钮
List {
Button(action:{
}) {
Text("Add Room")
}
// ForEach为它的每个集结项都创立一个视图
ForEach(store.rooms) { room in
RoomCell(room: room)
}
}
Button(action:addRoom) {
Text("Add Room")
}
func addRoom() {
store.rooms.append(Room(name: "Hall 2", capacity: 2000))
}
修正List的样式
修正listStyle
NavigationView {
List {
//
}
.navigationBarTitle(Text("Rooms"))
.listStyle(GroupedListStyle())
}
设置分组
List {
Section {
Button(action:addRoom) {
Text("Add Room")
}
}
Section {
ForEach(store.rooms) { room in
RoomCell(room: room)
}
}
}
支撑动态删去
func delete(at offsets: IndexSet) {
store.rooms.remove(atOffsets: offsets)
ForEach(store.rooms) { room in
RoomCell(room: room)
}
.onDelete(perform: delete)
设置NavigationBarItem
NavigationView {
List {
}
.navigationBarItems(trailing: EditButton())
}
支撑列表从头排序
func move(from source: IndexSet, to destination: Int) {
store.rooms.move(fromOffsets: source, toOffset: destination)
}
ForEach(store.rooms) { room in
RoomCell(room: room)
}
.onDelete(perform: delete)
.onMove(perform: move)
设置预览环境
Group {
ContentView()
.environmentObject(RoomStore(rooms: testData))
// 大字号环境
ContentView()
.environmentObject(RoomStore(rooms: testData))
.environment(.sizeCategory, .extraExtraLarge)
// 深色方法
ContentView()
.environmentObject(RoomStore(rooms: testData))
.environment(.colorScheme, .dark)
// 布局方向
ContentView()
.environmentObject(RoomStore(rooms: testData))
.environment(.layoutDirection, .rightToLeft)
.environment(.locale, Locale(identifier: "ar"))
}
总结
SwiftUI四个首要规划准则:
- Declarative
- Compositional
- Automatics
- Consistent