系统: Mac OS 10.15.1, XCode 11.2.1,swift 5.0
写作时间:2019-11-26
本文代码实现WWDC2019 视频Introducing SwiftUI: Building Your First App,改进的地方在于用XCode 11.2.1实现,视频上的内容是在XCode 11 beta上实现,有些api已经废弃。
新建Project,命名为RoomWWDC204。
细节请参考 SwiftUI实战:一统江湖的新框架
在SwiftUI中数据是第一等公民,这里先创建数据类Room
import SwiftUI
struct Room: Identifiable {
var id = UUID()
var name: String
var capacity: Int
var hasVideo: Bool = false
var imageName: String {
return name
}
var thumbnailName: String {
return name + "Thumb"
}
}
#if DEBUG
let testData = [
Room(name: "room-1", capacity: 6, hasVideo: true),
Room(name: "room-2", capacity: 8, hasVideo: false),
Room(name: "room-3", capacity: 16, hasVideo: true),
Room(name: "room-4", capacity: 10, hasVideo: true),
Room(name: "room-5", capacity: 12, hasVideo: false),
Room(name: "room-6", capacity: 8, hasVideo: false),
Room(name: "room-7", capacity: 10, hasVideo: true),
Room(name: "room-8", capacity: 7, hasVideo: false),
Room(name: "room-9", capacity: 1, hasVideo: false),
]
#endif
解析:
为了实现增删改查数据,数据可以逐层传递下去.
创建类RoomStore
import SwiftUI
import Combine
import Foundation
class RoomStore: ObservableObject {
@Published var rooms: [Room]
init(rooms: [Room]) {
self.rooms = rooms
}
}
新建Cell页面RoomDetail
,
import SwiftUI
struct RoomDetail: View {
let room: Room
@State private var zoomed = false
var body: some View {
ZStack(alignment: .topLeading) {
Image(room.imageName)
.resizable()
.aspectRatio(contentMode: zoomed ? .fill : .fit)
.navigationBarTitle(Text(room.name), displayMode: .inline)
.onTapGesture {
withAnimation(.easeInOut(duration: 2)) {
self.zoomed.toggle()
}
}
.frame(minWidth: 0, maxWidth: .infinity, minHeight: 0, maxHeight: .infinity)
if room.hasVideo && !zoomed {
Image(systemName: "video.fill")
.font(.title)
.padding(.all)
.transition(.move(edge: .leading))
}
}
}
}
#if DEBUG
struct RoomDetail_Previews: PreviewProvider {
static var previews: some View {
Group {
NavigationView {
RoomDetail(room: testData[0])
}
NavigationView {
RoomDetail(room: testData[1])
}
}
}
}
#endif
解析:
这个页面可以单独预览(快捷键: Command + Option + p), 这里用Group可以同时预览两个页面。
第一个hasVideo = true
, 左上角有摄像头。
第二个hasVideo = false
. 左上角有没有摄像头。
@State
根据属性去控制界面self.zoomed.toggle()
数据流
数据权限 | Source of Truth | Derived Value |
---|---|---|
只读 | Constant | Property |
读写 | @State ObservableObject |
@ObservedObject |
tableview在这里就是List
//
// ContentView.swift
// RoomWWDC204
//
// Created by zgpeace on 2019/11/24.
// Copyright © 2019 zgpeace. All rights reserved.
//
import SwiftUI
struct ContentView: View {
@ObservedObject var store = RoomStore(rooms: [])
var body: some View {
NavigationView {
// List(store.rooms) { room in
List {
Section {
Button(action: addRoom) {
Text("Add Room")
}
}
Section {
ForEach(store.rooms) { room in
RoomCell(room: room)
}
.onDelete(perform: delete)
.onMove(perform: move)
}
}
.navigationBarTitle(Text("Rooms"))
.navigationBarItems(trailing: EditButton())
.listStyle(GroupedListStyle())
}
}
func addRoom() {
store.rooms.append(Room(name: "Hall 2", capacity: 2000))
}
func delete(at offsets: IndexSet) {
store.rooms.remove(atOffsets: offsets)
}
func move(from source: IndexSet, to destination: Int) {
store.rooms.move(fromOffsets: source, toOffset: destination)
}
}
struct RoomCell: View {
let room: Room
var body: some View {
NavigationLink(destination: RoomDetail(room: room)) {
Image(room.thumbnailName)
.cornerRadius(8)
VStack(alignment: .leading) {
Text(room.name)
Text("\(room.capacity) people")
.font(.subheadline)
.foregroundColor(.secondary)
}
}
}
}
#if DEBUG
struct ContentView_Previews: PreviewProvider {
static var previews: some View {
Group {
ContentView(store: RoomStore(rooms: testData))
ContentView(store: RoomStore(rooms: testData))
.environment(\.sizeCategory, .extraExtraExtraLarge)
ContentView(store: RoomStore(rooms: testData))
.environment(\.colorScheme, .dark)
ContentView(store: RoomStore(rooms: testData))
.environment(\.layoutDirection, .rightToLeft)
}
}
}
#endif
解析:
GroupedListStyle()
样式运行效果:
图片展示的是group里的第三种,黑暗模式ContentView(store: RoomStore(rooms: testData)) .environment(\.colorScheme, .dark)
以前用UIKit的时候 Controller是控制中心,数据流比较复杂. 导致Controller膨胀很大。
导致UI Bugs出现不可控
事件状态转换、调用相当频繁
导致页面跟数据不同步
SwiftUI 只有body struct
, 把状态统一为一种类型
细节请移步WWDC,WWDC的讲解包括UI的交互和原理。
推荐Mac观看WWCD的软件:WWDC for macOS
https://github.com/zgpeace/RoomWWDC204/tree/master
WWDC
https://developer.apple.com/videos/play/wwdc2019/204/
课件下载
https://devstreaming-cdn.apple.com/videos/wwdc/2019/204isgnpbqud244/204/204_introducing_swiftui_building_your_first_app.pdf
https://www.raywenderlich.com/3868932-wwdc-2019-top-10-videos
https://wwdc.io/