用SwiftUI写程序

一:编写第一个SwiftUI程序

1,创立SwiftUI工程

image.png

-左面是代码区

-右侧是Canvas

编写代码时,右侧的Canvas可以实时显示出代码的UI预览效果

image.png

2,编写UI布局代码

经过拖拽添加UI控件


image.png

VStack:SwiftUI常用的一种布局元素,可以用来垂直地叠加视图
HStack:水平叠加视图


image.png
HStack {
VStack {
Text("Rooms")
Text("20 people")
}
}

在文字左面添加一个图片

HStack {
// `photo`是体系自带资源库中的图片
Image(systemName: "photo")
VStack {
Text("Rooms")
Text("20 people")
}
}

在Canvas中将VStack修正为左对齐


image.png

设置Text的字号


image.png
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


image.png

image.png

3,设置数据源

添加Room模型

在SwiftUI中,需要让模型遵照Identifiable协议,完结id特征


image.png

在ContentView中运用Room数据来展现UI


image.png

4,丰富UI内容

设置图片圆角

经过拖拽Modifier库来完结


image.png

设置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"))
}

进入实时方法,查看效果


image.png

将子视图提成一个单独的视图


image.png

创立新的页面: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的展现方法


image.png

将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状态变量的视图时,它会以视图的名义为那个变量分配存储空间。

image.png

绿色部分是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)


image.png

zoomed变量是一个实际来历,contentMode衍生自它,当体系观察到zoomed变量产生变化时,SwiftUI结构会请求新的body,改写烘托,从头生成一个新的宽高比视图,接下来覆盖contentMode。
数据流原语(Data Flow Primitives)


image.png

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.png

固定图标的方位

Image(room.imageName)
.frame(minWidth:0, maxWidth: .infinity, minHeight: 0, maxHeight: .infinity)
image.png

一同预览多个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))
}
image.png

给图片的动效延伸时刻

.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)
}
}
image.png
Button(action:addRoom) {
Text("Add Room")
}
func addRoom() {
store.rooms.append(Room(name: "Hall 2", capacity: 2000))
}
image.png

修正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)
image.png

设置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)
image.png

设置预览环境

        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

SwiftUI运用陈说性语法

在SwiftUI中,Xcode预览可以让咱们阅读、修正和调试APP,咱们乃至不需要工作项目工程

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 194,242评论 5 459
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 81,769评论 2 371
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 141,484评论 0 319
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 52,133评论 1 263
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 61,007评论 4 355
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 46,080评论 1 272
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 36,496评论 3 381
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 35,190评论 0 253
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 39,464评论 1 290
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 34,549评论 2 309
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 36,330评论 1 326
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 32,205评论 3 312
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 37,567评论 3 298
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 28,889评论 0 17
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,160评论 1 250
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 41,475评论 2 341
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 40,650评论 2 335

推荐阅读更多精彩内容