一起养成写作习惯!这是我参与「掘金日新计划 · 4 月更文挑战」的第17天,点击查看活动详情。
- 本文主要介绍下
SwiftUI的概念和简单使用
1. 关于SwiftUI
2019年WWDC大会上,苹果在压轴环节向大众宣布了基于Swift语言构建的全新UI框架——SwiftUI,开发者可通过它快速为所有的Apple平台创建美观、动态的应用程序。
SwiftUI在iOS13、macOS10.15、tvOS13和watchOS6上运行。而且SwiftUI的运行速度优于UIKit,他减少了界面的层次结构,因此减少了绘制步骤,并且他完全绕过了CoreAnimation,直接进入Metal。
2. 什么是SwiftUI?
Swift UI,官方的定义很好找到,也写得非常明确:
SwiftUI is a user interface toolkit that lets us design apps in a declarative way.
可以理解为 SwiftUI 就是⼀种描述式的构建 UI 的⽅式。
SwiftUI是一个用户界面开发工具包,它让我们使用声明式(declarative)编程的方式设计应用。这是一种很酷的说法,他的意思其实就是:我们需要告诉SwiftUI,我们的UI应该长成什么样子;当用户和它互动(interact)的时候,我们的UI应该如何反应。
SwiftUI 作为 Apple 在自家平台使用 Swift 语言打造的首个重量级系统框架,将为这个平台上用户界面的构建方式带来革命性的转变。它摒弃了从上世纪八十年代开始就一直被使用的指令式 (imperative) 编程的方式,转而向投声明式 (declarative) 编程的阵营,这提高了我们解决问题时所需要着手的层级,从而让我们可以将更多的注意力集中到更重要的创意方面。
3.为什么苹果要推出SwiftUI
在 SwiftUI 出现之前,苹果不同的设备之前的开发框架并不互通,移动端的⼯程师和桌⾯端的⼯程师需要掌握的知识,有很⼤⼀部分是差异化的。比如iOS、macOS、WatchOS,这种碎片化的开发体验无疑会大大增加开发者所需消耗的时间精力,也不利于构建跨平台的软件体验。苹果希望直接优化语言本身,并统一所有设备的开发体验,让开发者更容易上手,也更容易将心里的想法转化为运行的程序。
除了统一终端以外,苹果也在想方设法增加开发者的数量,提升单个应用质量。方式也非常符合第一性思维原则——降低开发的难度。所以先有了 Swift,紧接着又推出了 SwiftUI,因为之前的UIKit是有很大的局限性的,UIKit 的基本思想要求 ViewController 承担绝⼤部分职责,它需要协调 model,view 以及⽤⼾交互。这带来了巨⼤的 sideeffect 以及⼤量的状态,如果没有妥善安置,它们将在 ViewController 中混杂在⼀起,同时作⽤于 view 或者逻辑,从⽽使状态管理愈发复杂,最后甚⾄不可维护⽽导致项⽬崩溃。换句话说,在不断增加新的功能和⻚⾯后,同⼀个ViewController会越来越庞杂,很容易在意想不到的地⽅产⽣ bug。⽽且代码纠缠在⼀起后也会⼤⼤降低可读性,伤害到维护和协作的效率。
SwiftUI 使用了大量 Swift 的语言特性,特别是 5.0 之后新增的特性。Swift 5.1 的很多特性几乎可以说都是为了 SwiftUI 量身定制的,比如 Opaque return types、Property Delegate 和 Function builder 等。
在 SwiftUI 出现之前,苹果不同的设备之前的开发框架并不互通,移动端的⼯程师和桌⾯端的⼯程师需要掌握的知识,有很⼤⼀部分是差异化的。比如iOS、macOS、WatchOS,这种碎片化的开发体验无疑会大大增加开发者所需消耗的时间精力,也不利于构建跨平台的软件体验。苹果希望直接优化语言本身,并统一所有设备的开发体验,让开发者更容易上手,也更容易将心里的想法转化为运行的程序。
4. 使用体验
我们仿照下AppStore的页面写下这个页面
let ScreenWidth = UIScreen.main.bounds.width
let ScreenHeith = UIScreen.main.bounds.height
let img1 = "https://is1-ssl.mzstatic.com/image/thumb/Rr95SN7K-szrYIDRV2YgOg/626x392sr.webp"
let img2 = "https://is1-ssl.mzstatic.com/image/thumb/Purple112/v4/3a/fc/ad/3afcad41-5d73-0257-222e-b07f62c0606d/AppIcon-1x_U007emarketing-0-6-0-85-220.png/160x160sr.webp"
struct ContentView: View {
@State var items: [String] = Array(0...2).map { "Item \($0)" }
var body: some View {
NavigationView {
ScrollView {
VStack {
Divider().padding(EdgeInsets.init(top: 20, leading: 20, bottom: 0, trailing: 20))
.overlay {
AsyncImage(url: URL.init(string: img2), content: { img in
img.resizable()
}, placeholder: {
ProgressView()
}).frame(width: 50, height: 50).cornerRadius(25)
.overlay {
Text("1").frame(width: 32, height: 20).background(.red).cornerRadius(10).foregroundColor(.white).padding(EdgeInsets.init(top: -30, leading: 30, bottom: 0, trailing: 0))
}.padding(EdgeInsets.init(top: -64, leading: 300, bottom: 0, trailing: 0))
}
TabView {
ForEach($items, id: \.self) {_ in
VStack {
HStack {
Text("畅玩新赛季").foregroundColor(.blue).fontWeight(.bold)
Spacer()
}
HStack {
Text("王者荣耀").font(.title)
Spacer()
}
HStack {
Text("全新英雄“桑启”登场").font(.title2).foregroundColor(.gray)
Spacer()
}
AsyncImage(url: URL.init(string: img1)) { img in
img.resizable()
} placeholder: {
ProgressView()
}
.frame(height: 220)
.cornerRadius(10)
.overlay {
VStack {
Spacer()
HStack {
AsyncImage(url: URL.init(string: img2)) { img in
img.resizable()
} placeholder: {
ProgressView()
}
.frame(width: 50, height: 50).cornerRadius(12)
VStack {
HStack {
Text("王者荣耀").foregroundColor(.white).font(.title3)
Spacer()
}
HStack {
Text("S27赛季 萤火不灭").foregroundColor(.gray)
Spacer()
}
}
Spacer()
VStack {
Button("获取") {
print("get")
}.foregroundColor(.white).font(Font.system(.title2).bold()).frame(width: 94, height: 40).background(.gray.opacity(0.8)).cornerRadius(20)
Text("App内购买").foregroundColor(.gray).font(.footnote)
}.padding(.top, 15)
}
.padding(EdgeInsets.init(top: 0, leading: 16, bottom: 6, trailing: 16))
.background(LinearGradient(colors: [.black.opacity(0.5), .clear], startPoint: .bottom, endPoint: .top)).cornerRadius(12)
}
}
}.padding(20)
}
}
.frame(width: ScreenWidth, height: 320)
.tabViewStyle(PageTabViewStyle(indexDisplayMode: .never))
Divider().padding(EdgeInsets.init(top: 25, leading: 20, bottom: 0, trailing: 20))
VStack {
HStack {
Text("我们都在玩").font(.title).bold()
Spacer()
Button("查看全部") {
print("all")
}.font(.title2)
}
HStack {
Text("探索本周游戏热点").foregroundColor(.gray).font(.title2)
Spacer()
}
}.padding(EdgeInsets.init(top: 0, leading: 20, bottom: 0, trailing: 20))
TabView {
ForEach($items, id: \.self) {_ in
List(0..<3) {_ in//遗留:禁止滑动,同学自行处理
HStack {
AsyncImage(url: URL.init(string: img1)) { img in
img.resizable()
} placeholder: {
ProgressView()
}
.frame(width: 68, height: 68).cornerRadius(16)
VStack {
HStack {
Text("王者荣耀").font(.title3)
Spacer()
}
HStack {
Text("S27赛季 萤火不灭").foregroundColor(.gray)
Spacer()
}
}
Spacer()
VStack {
Button("获取") {
print("get")
}.foregroundColor(.blue).font(Font.system(.title2).bold()).frame(width: 94, height: 40).background(.gray.opacity(0.2)).cornerRadius(20)
Text("App内购买").foregroundColor(.gray).font(.footnote)
}
}
}.listStyle(InsetListStyle())//.listRowSeparator(.hidden)
}
}
.frame(width: ScreenWidth, height: 270)
.tabViewStyle(PageTabViewStyle(indexDisplayMode: .never))
// Spacer()
}
}
.navigationTitle("游戏")
}
}
}
运行效果:
基本上很简单的代码就达到了复杂的界面效果,更加快速。
总结
SwiftUI就是swift+UI的结合,进行快速搭建页面。通过combine进行响应式编程,大大提高了我们的效率。我们在开发中,修改后立马可以看到更改的效果,类似热更新。布局的效果类似前端的盒子式的布局方式,符合我们的感官。