暂无图片
暂无图片
暂无图片
暂无图片
暂无图片

SwiftUI-声明式UI框架实践

AggrxTech 2021-08-27
4812

简介

在SwiftUI发布之前,iOS平台上UI开发都是围绕着UIKit框架,相关的技术包括:autoresizing、约束布局、UIStoryboard、XIB,开发方式分为可视化的InterfaceBuilder和直接Coding。不过这些技术和方法都无法避免开发者陷入屏幕尺寸适配的细节当中...

除了适配多个屏幕尺寸,如果开发者可以把应用发布到多个平台:macOS、watchOS、tvOS、iPadOS。对苹果和开发者来说都将创造更大的价值,因为平台存差异的存在,支持2个以上平台对大部分开发者来说都是“不可能的任务”,大部分团队都会安排专人负责平台适配。

SwiftUI是如何做到跨平台?实际体验和效果如何?开发者应该怎样对待SwiftUI?对于SwiftUI这种影响巨大的技术来说,如果想彻底了解技术本身,需要阅读专门的教程和官方文档,在这遍介绍中我从“大处着眼”,谈谈对SwiftUI的一些认识和想法,方便读者结合自己的实际情况加以抉择。

SwiftUI是什么

官方定义:

SwiftUI is a modern way to declare user interfaces for any Apple platform.

SwiftUI是Apple全平台声明式构建UI的开发工具。

苹果为什么要推出SwiftUI

开发高品质的产品

智能设备高度普及的今天,苹果产品在市场中赢得用户的一个重要原因就是:从硬件到软件,苹果产品总是给人感觉:协调一致、浑然天成。

从硬件来看,这种感觉营造归功于苹果的工业设计,从Mac电脑到iWatch手表,苹果用同一套设计思想,为用户提供了一致化体验的高品质硬件设备,从外观到手感都是一流的。从软件角度来看,各种软件在满足用户各种需求的同时,保持一致的交互和流畅的动画,更让用户在多个应用中切换、协作,毫无违和之感,极大的降低了使用学习成本。

为了保证应用的协调、统一,苹果为开发者提供了一套良好封装的编程框架,其中包含经典的ObjC/Swift语言、MVC设计模式、简洁易用的动画接口、以及其他满足各种开发需求的API;除此之外还苹果还有一套业界广为认可的《人机交互指南》,开发者和设计师在这套指南的指导下,开发出符合用户使用习惯和直觉的应用,随着系统的升级不断更新;在应用提交到应用商店之后,商店会按照《App审核指南》对应用进行审核,这将确保只有符合了苹果质量和体验要求的应用才能上架。

UI开发的核心

在应用开发当中,我们更加关心内容的呈现,这种呈现在SwiftUI之前,几乎都是由开发者负责的。拿显示一段文字来举例子,开发者需要告知运行时UILabel需要显示哪些文字、字体、文字颜色、位置、显示范围尺寸等信息,为了适配不同尺寸的屏幕,苹果还提供了自动布局框架,让开发者可以依据屏幕动态的调整视图的位置、尺寸,开发者还需要使用SafeArea等API,确保内容的可读性及交互。

上述问题仅仅是面对单个平台需要处理的。要知道苹果的产品还包括Mac、AppleTV、iPad、iPhone、iWatch等诸多平台,在不同平台开发还有不同UI框架……

UI开发的核心是什么?

对于开发者来说,UI开发的核心问题就是:开发者需要聚焦到业务之上,处理用户交互,根据业务数据更新内容。而适配屏幕、处理安全区域和系统差异这些工作都是由运行时负责的。

SwiftUI的组成部分

声明式构建UI

在UIKit中构建UI的方式可以概括为“自说自画”,就是说不光要知道界面需要呈现什么数据,还需要知道这些内容如何被命令化的方式绘制到屏幕上。这种方式自图形用户界面发明以来延续至今,其优缺点都是显而易见的:优点在于符合计算机原理,更容易被解释执行、提升效率;缺点在于不直观、缺少抽象、平台依赖,最明显的影响就是当平台功能有重大升级时,需要适配开发。

声明式构建UI对内容呈现过程进行抽象:不再需要使用平台相关的组件(配置组件数据、设置其布局尺寸),开发者只提供由数据到界面的一套描述。在下图中可以直观的看出,直接使用SwiftUI提供的基本组件呈现数据,UI布局、屏幕适配都由系统负责。这种开发方式就是“声明式构建UI”。在Demo中仅用了270行左右代码,就实现了一个复杂Feed流的界面的高保真可交互原型,同样的功能使用UIKit实现代码量会成倍增加。

从Demo中Feed流页面中可以看到,整个界面分为两层,分别是下层顶部的粉色区域还有顶层占满屏幕的VStack。VStack分为三部分:搜索入口、顶部分类标题、内容区。内容区由4种内容填充:banner、图文按钮、书籍样式1、书籍样式2。可以直观的看出来,代码结构和最终呈现的界面结构上是一致的,在书籍样式中清晰的体现出,数据和视图的自然绑定。相比UIKit中的CollectionView和TableView加数据源/代理的结构,代码不再被拆分为协议的多个方法回调,还省去了注册可复用视图。

中部图片文字按钮区对应在UIKit当中类似的UI应该是UICollectionView负责,每一项对应到UICollectionViewCell。到了Swift UI中由LazyHGrid承载,每一项都是VStack,通过打破UIKit中这种固定关联,让几个基础原件外的视图可以任意组合,而作为嵌套子视图的元素可以是任意的视图,其中的ForEach使用函数式编的编程方式,按照数据生成嵌套的子视图,不仅含义清晰,开发效率也大幅度提高。

书籍样式当中仅对内容宽高比和内容间隔做出说明,这种方式确保在不同屏幕尺寸下,内容始终保证显示的比例,其位置和实际大小则由容器控制,对于UI来说顶层的容器尺寸实际上就是屏幕尺寸,这就是SwiftUI可以适配任意尺寸设备的基础。

 

MVVM和数据流

对开发者来说,保持清晰的数据流,是减少问题的一个重要前提,MVC模式中缺乏对数据的整体性管理,一个控制器的视图状态可能由多个方法和多个数据在某个执行时序下产生。当Bug出现时,很难追溯产生错误的原因。

在SwiftUI中MVVM则成为了标准配置,其中View是无状态的、声明式的,只能呈现Model的映射,ViewModel一方面负责把Model转换成View需要的数据格式,然后把这些转换好的数据派发出来,各个View根据需要自行订阅获取相应的数据;另一方面ViewModel负责接收View的Indent调用,更新Model。

ViewModel作为的Model编辑者,不仅是单例,并且在View中逐层传递,确保了Model的编辑只会从唯一的ViewModel发起,保证了数据的流向不会存在交叉。

自动适配不同平台

Write Once, Run Anywhere.这曾经是Java语言的宣传口号,在各个平台安装相应的虚拟机就可以运行相同的程序。这种对程序本身的复用正是软件开发中一直提倡的。如今在苹果的生态中,SwiftUI承担起了这个责任。

在当下各种智能设备层出不穷,从智能手机到智能家居,正是因为SwiftUI的代码逻辑仅聚焦于业务不涉及平台细节,从理论上来说现有的和新的设备都能够部署开发者的应用。各个平台在为应用生成UI时,可以按照屏幕尺寸自行决定UI排版,还可以按照平台以及设备特性选择适合的控件进行渲染,甚至每个平台还可以使用不同的交互方式。

Combine响应式编程

UIKit框架中数据改变后同步到界面的方式有KVO和通知两种机制,即使开发者非常有经验,但面对复杂的业务需求时往往也力不从心,在一些项目中还能看到修改完数据后手动更新UI的情况,在应用迭代几个版本之后,出现的问题修复起来就很困难了。

为了解决数据的流动方向的问题,涌现了很多以数据流动为核心的三方框架,如RxSwift、RAC,这些三方库需要对UIKit中的各种事件、通讯重新封装为“信号”。Combine则是苹果官方实现的响应式编程框架,通过观察者模式订阅数据流的变化,从Swift语言和运行时两个维度得到支持,代码也更符合人类语言的表达习惯。在SwiftUI中,View作为Combine框架中的观察者,订阅了相应的数据,在数据变化后,通知系统刷新变化的部分。

函数响应式编程使用预置的一套规则,系统在数据更新时销毁需要更新的视图,然后生成新的视图,UI实际上成为了数据的映射,这也就解决了单一数据源的问题。在Flutter等一些跨平台解决方案中,响应式编程也成为了主流。

视图组件化:UI重用

在使用UIKit的项目中,如果某个视图控制器在A需求中是独立页面,到了B需求中是嵌套在某个页面中的一个弹窗,这种情况是需要做大量适配工作的,而在SwiftUI中,移除了视图控制器,这使得SwiftUI中的视图层级是单一元素组成的树形结构,在树形结构中,从任意一个节点都可以生成可复用的复杂组件。

UIKit是预先存储生成好的视图层级,SwiftUI则是利用计算生成的视图层级,后者天然就具备动态性,这种动态性完全满足数据变化和屏幕尺寸的适配需求。

与UIKit交互

和当初Swift早期的一样,SwiftUI还在发展完善的过程中,虽然官方的说法99%的UI布局都可以实现,剩下1%无法实现的部分可能还需要UIKit来完成。如果需要把UIKit提供给SwiftUI使用的话,UIKit实现只需要遵循UIViewRepresentable协议即可,反过来UIKit也可以调用SwiftUI构建的页面。SwiftUI的兼容性使得开发者可以安心使用UIKit实现好的部分,结合SwiftUI开发新的功能。

开发人员该怎么做

相比Swift语言的发展过程,SwiftUI从推出到承担App开发的过程短的多,一方面Swift步入了成熟期,另外一方面声明式构建UI的理论和实践也不断完善,苹果一直以来的作风都是不做第一个尝试者,但解决方案的落地和成熟度总是在业内领先。

有人认为SwiftUI是为了和Flutter争夺开发者,但笔者认为苹果一向是技术为产品体验服务的,跨平台技术在性能和产品体验方面始终是无法撼动原生开发工具地位的。近些年我们也能看到苹果在硬件和操作系统方面相互融合所做的努力:推出M1芯片的Mac,允许iPad应用安装到Mac系统上。

SwiftUI对开发者来说是挑战也是机会,我们看到安卓平台在同期也推出了Jetpack Compose,声明式构建UI让开发者更加专注于要解决的问题,再辅以热更新(预览)功能,以往需要数小时才能完成的需求,SwiftUI实现可能1小时内就能完成。由于SwiftUI相对UIKit的开发效率得到极大提升,对于新的项目来说,SwiftUI无疑应该作为首选,因为新的项目需要快速实现、快速功能迭代,以便把各种想法投放到市场加以验证。对于需要迭代更新的现有项目,从市场角度来说因为使用iOS13以下版本的用户比重还很高,还无法引入SwiftUI。对成熟的开发者来说在某种技术开始之初就逐步加以熟悉,这样可以更多的了解其背后的原理,在技术成熟之后使用起来才会更加得心应手。

对设计师来说,需要避免在设计上出现像素级别的控制,做出的设计应该在符合规范的前提下突出应用需要呈现的内容本身,因为声明式的布局和我们的表达习惯非常贴合,所以SwiftUI学习的门槛并不高,加上预览功能的即时反馈,设计师在简单的学习之后,可以直接生成UI感受交互效果,节约和开发的沟通成本。

本文是作者对SwiftUI的一些认识和理解,难免有谬误之处,欢迎指正一起进步。

 


文章转载自AggrxTech,如果涉嫌侵权,请发送邮件至:contact@modb.pro进行举报,并提供相关证据,一经查实,墨天轮将立刻删除相关内容。

评论