SwiftUI-01- 初识SwiftUI

410 阅读5分钟

一起养成写作习惯!这是我参与「掘金日新计划 · 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的页面写下这个页面

IMG_1D05363FC04B-1.jpeg


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("游戏")

        }

    }

}

运行效果:

image.png

基本上很简单的代码就达到了复杂的界面效果,更加快速。

总结

SwiftUI就是swift+UI的结合,进行快速搭建页面。通过combine进行响应式编程,大大提高了我们的效率。我们在开发中,修改后立马可以看到更改的效果,类似热更新。布局的效果类似前端的盒子式的布局方式,符合我们的感官。