教你快速使用 SwiftUI 开发 App

SwiftUI

SwiftUI 是一种非常简单的创新方法,可以利用 Swift 的强大能力在所有苹果设备平台上构建用户界面。通过 SwiftUI,开发者仅使用一组工具和 API 就能为所有苹果设备构建用户界面。SwiftUI 使用易于阅读和编写的声明式 Swift 语法,可与新的 Xcode 设计工具无缝协作,使你的代码和设计完美同步。SwiftUI 自动支持动态类型、深色模式、本地化和可访问性,你的 SwiftUI 代码将成为你写过的最强大的 UI 代码。

目标

实现一个列表,点击列表的 item,跳转到对应的详情页。

根据苹果官方教程,整理了 SwiftUI Sample

SwiftUI Sample Preview

首先回想一下在 UIKit 中如何实现:

  • 创建一个带导航 Navigation 的 controller,用来布局和 Push 下一个页面。
  • 添加 UITableView,并实现 UITableView 的两个代理方法,展示列表。
  • 创建 UITableViewCell,布局 UILabel 和 UIImageView。
    创建详情页面,布局地图、三个 UIlabel。
  • 在 UITableViewDelegate 的代理方法中 Push 到详情页。
  • 对 iOS 开发来说这太简单太熟悉不过了,但很多代码比较繁琐,控件的创建、布局等。虽然简单,但繁琐,浪费了很多本该花在业务上的时间。

在 SwiftUI 中怎么实现呢?

在实现之前,先看一下所需要的组件,按照用途大致分为基础组件、布局组件和功能性组件,以及 XCode11 提供的新功能。

所需组件

基础组件
  • Text 用来显示文字 类似于 UIKit 中的 UILabel
  • Image 用来显示图片 类似于 UIKit 中的 UIImageView
  • Spacer 用来填充空白
布局组件
  • VStack 竖直摆放的组合组件
  • HStack水平摆放的组合组件
  • List 用来展示列表 类似于 UIKit 中的 UITableView
功能型组件

NavigationView 展示导航栏类似于 UINavigationBar
NavigationLink 类似于 pushViewController: 方法

XCode11相关功能

预览

实时看到对页面的做出的修改

  • 纯 SwiftUI 时,默认静态预览。

点击预览串口的 Resume 按钮。

如果没有显示预览窗口,则按下图操作打开。

  • 预览包含 UIView 子类视图时,需要打开时时预览

点击可以切换时时预览和静态预览。

拖放

command 键 + 鼠标点击组件,可以方便的添加组件,设置组件属性等。

代码实现

创建列表
struct LandmarkList : View {
    var body: some View {
        // 自定义显示的内容
        List(0 ..< 5) { item in
            Text("hello")
                .font(.title)
        }
    }
}

使用 List 组件可以快速的创建滑动列表,不需要设置代理,不需要实现协议方法就达到类似于 UIKit 中 UITableView 的效果。

Text 用来展示文字,通过 .font 设置了字体大小。将它放入 List 中,它就是列表的 Item。

从工程 Resources 文件夹中找到资源文件,引入工程,里面包含了 json 数据、图片等。再引入 Models 文件夹中的 Data.swiftLandmark.swift,这些主要是为了组件数据和 Model,不是本文讨论的重点,下面会用到这些数据。

创建 Item

这一步在 UIKit 中像自定义 UITableViewCell,需要再其中添加一个图片和一个文字。

在 SwiftUI 中,没有 UITableViewCell 的概念,需要显示一行的时候,只需要使用 HStack 组件,HStack 组件是一个组合组件,其中可以放 TextImage 等组件。

创建 LandmarkRow

struct LandmarkRow : View {
    var landmark: Landmark
    
    var body: some View {
        HStack {
            landmark.image(forSize: 50)
            Text(landmark.name)
        }
    }
}

landmark.image(forSize: 50) 这个方法返回一个指定大小的图片

Text 显示地标名称。

HStack 将图片和文字组合在一行里面显示,并配置的有默认格式。

效果:

把它带入第一步创建的列表中,并引入数据。

struct LandmarkList : View {
    var body: some View {        
        List(landmarkData) { landmark in
            LandmarkRow(landmark: landmark)
        }   
    }
}

效果:

列表已经显示出来了。

想想 UIKit 中的那堆代码,是不是暗爽?

创建详情页

从效果图中看到详情页有一个地图、一个圆形图片、几个显示地名、位置的文字。

从布局上看最下面两个水平的文字可以摆放在水平组件中,再和标题文字一起摆放在竖直组件中。

地图、图片、水平摆放的组件再一起摆放在竖直摆放组件中。

创建地图模块:

struct MapView : UIViewRepresentable {
    
    var coordinate: CLLocationCoordinate2D
    
    func makeUIView(context: Context) -> MKMapView {
        MKMapView(frame: .zero)
    }
    
    func updateUIView(_ view: MKMapView, context: Context) {
        let span = MKCoordinateSpan(latitudeDelta: 0.02, longitudeDelta: 0.02)
        let region = MKCoordinateRegion(center: coordinate, span: span)
        view.setRegion(region, animated: true)
    }
}

要在 SwiftUI 中添加非 SwiftUI 的组件,需要遵循 UIViewRepresentable 协议,并实现协议方法。

创建圆角图片:

struct CircleImage : View {
    
    var image: Image
    
    var body: some View {
        image
        .clipShape(Circle())
        .overlay(
            Circle().stroke(Color.white, lineWidth: 4)
            .shadow(radius: 10)
        )
    }
}

创建详情页

struct LandMarkDetail : View {
    var landmark : Landmark
    
    var body: some View {
        VStack {
            MapView(coordinate: landmark.locationCoordinate).frame(height: 300)
            CircleImage(image: landmark.image(forSize: 250))
                .offset(y: -130)
                .padding(.bottom, -130)
            
            // 三个文字
            VStack(alignment: .leading) {
                Text(landmark.name)
                    .font(.title)
                // 下面两个文字
                HStack {
                    Text(landmark.park)
                        .font(.subheadline)
                    Spacer()
                    Text(landmark.state)
                        .font(.subheadline)
                }
                }
                .padding()
            Spacer()
        }
    }
}

VStack 竖直组合组件,里面包含了 MapViewCircleImage 以及 VStack

VStack 中包含了标题文字以及HStack

HStack 中包含了水平摆放的两个文字组件。

效果:

实现跳转

上面已经分别实现了列表页和详情页面,下面实现跳转。

UIKit 中想要 Push 效果需要创建 UINavigationController ,想要显示导航栏需要设置 UINavigationBar,想要跳转需要在 UITableView 的代理方法中调用 pushViewController: 方法。

修改上面创建的列表:

struct LandmarkList : View {
    var body: some View {
        NavigationView {
            List(landmarkData) { landmark in
                NavigationLink(destination: LandmarkDetail(landmark: landmark)) {
                    LandmarkRow(landmark: landmark)
                 }
                }
                .navigationBarTitle(Text("Landmarks"), displayMode: .inline)
        }
    }
}

NavigationView 组件类似于 UINavigationBar,可以设置导航栏标题和模式。

NavigationLink 可以直接将跳转方法直接和列表展示绑定在一起,逻辑更清晰明了。

总结

了解过 Flutter 的同学对这个接受可能会很快。

没有了解过 Flutter 的同学需要转变一下页面布局思路。

SwiftUI 对 iOS 开发同学来是一大福音,毕竟都2019年了,还在使用 UIKit 中这么原始的布局,实在是苦不堪言。

SwiftUI 需要 iOS13 以上的系统,但目前公司开发 App 都会支持一定的老版本系统,还得使用 UIKit。全面使用 SwiftUI 预计还有一段时间。毕竟,还有很多公司没有使用 Swift 呢。

写的有不好的地方希望大家指出,我会更正,大家有什么看不明白的,也可以在评论里面提问,我会尽力解答。另附 Apple 官方 SwiftUI Tutorials


点赞+关注,第一时间获取技术干货和最新知识点,谢谢你的支持!

最后祝大家生活愉快~

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