SwiftUI简介
SwiftUI是苹果推出的一个新的UI框架,它使用了声明的方式,通过视图,基础控件和布局控件来进行页面的开发。
SwiftUI具有跨平台性,一份SwiftUI代码可以同时跑在iOS、macOS、tvOS、watchOS平台上。
SwiftUI编写的页面代码更简洁,广泛使用链式调用。
SwiftUI视图和UIKit视图可以互相转换,对于将旧的项目过度到新布局方式比较友好。
SwiftUI的运行速度优于UIKit,他减少了界面的层次结构,因此可以减少绘制步骤,并且他完全绕过了CoreAnimation,直接进入Metal,可以有优秀的渲染性能。
 
其实声明式页面布局前端已经出现了很久,像React, Vue都是使用的声明式布局,声明式布局与命令式布局相比有很多优势,
如:单向数据流,双向数据绑定,只要数据状态改变使用了这些数据的视图就会自动更新等。
声明式布局是UI布局方式的未来,这次苹果从命令式编程过度到声明式编程算是一个大的进步。
 
设计模式
采用Struct组成的树形结构组织页面。叶子节点是基本控件。
这棵Struct树类似于React的抽象语法树,它会在编译阶段将这些描述信息翻译成真实的UIKit中的UI控件。
 
视图结构
APP根入口
APP的根入口是一个Struct结构体,它遵守APP协议
@main
struct WorldLandMarkApp: App {
var body: some Scene {
WindowGroup {
ContentView()
}
}
}
App协议
public protocol App {
associatedtype Body : Scene @SceneBuilder @MainActor var body: Self.Body { get } @MainActor init()
}
页面结构体
some表示返回的是一个遵守了View协议的不透明类型,也就是var body: some View {} 这个计算属性中,只能return一种类型,不能出现if a {Text()} else {List{}} 这样的2种类型。
struct LandmarkList: View {
var body: some View {
Text(/*@START_MENU_TOKEN@*/"Hello, World!"/*@END_MENU_TOKEN@*/)
}
}
View协议
associatedtype Body : View 表示协议中定义了一个新类型Body,这个Body遵守View协议。
Self.Body 表示协议中的Body类型。Self表示类型本身,self表示实例变量本身
public protocol View {
associatedtype Body : View
@ViewBuilder @MainActor var body: Self.Body { get }
}
每个页面swift文件中都有2个结构体,一个表示要开发的页面,另一个是使用Canvas进行展示出来的视图,其中struct ContentView_Previews: PreviewProvider可以根据Debug需要在外层嵌套导航条,展示Group组。
import SwiftUI

struct ContentView: View {
var body: some View {
Text("Hello, world!")
.padding()
}
} struct ContentView_Previews: PreviewProvider {
static var previews: some View {
ContentView()
}
}
它们不一定保持一致,如:
struct LandmarkList_Previews: PreviewProvider {
struct DeviceType: Identifiable {
var id = UUID()
var name: String
} static var previews: some View {
//使用ForEach展示多个设备
ForEach([DeviceType(name: "iPhone 12"),DeviceType(name: "iPhone 13")]){ deviceItem in
LandmarkList().previewDevice(PreviewDevice(rawValue: deviceItem.name))
.previewDisplayName(deviceItem.name)
} }
}
状态双向绑定
@State单页面状态绑定
通过@State修饰的变量是做了双向绑定的,如果这个变量数据发生了改变,所有使用这个变量的视图都会自动更新。但是@State的修饰范围是当前的一个视图,如果想一个状态修改,整个APP范围内使用这个变量的视图全部都更新,则需要使用全局环境变量的模式。
@State private var isOpen
struct LandmarkList: View { @State private var isOpen: Bool = false
//@ObservedObject: 全局环境变量绑定
@ObservedObject var userData: UserData = UserData()
}
@ObservableObject+@Published全局状态变量
要使用全局状态变量,则需要创建一个class,并遵守ObservableObject协议。 然后在这个类中定义一个@Published修饰的变量 @Published var userLandmarks, 当@Published修饰的变量更新时,那么使用了@Published修饰的变量的视图就会对应更新。
定义一个UserData,遵守ObservableObject协议
import SwiftUI
import Combine class UserData: ObservableObject {
@Published var userLandmarks:[Landmark] = landmarks }
使用时,也要在对应的视图中加上 @ObservedObject修饰符,然后更新这个变量self.userData.userLandmarks[self.userLandmarkIndex].isFeatured.toggle()
struct LandmarkDetail: View {
var landmark: Landmark
@ObservedObject var userData: UserData var userLandmarkIndex: Int {
userData.userLandmarks.firstIndex(where: {$0.id == landmark.id})!
} var body: some View {
Button(action: {
self.userData.userLandmarks[self.userLandmarkIndex]
.isFeatured.toggle()
}){
if landmark.isFeatured {
Image("icon_rcxinhua_selected")
.resizable().frame(width: 20, height: 20, alignment: .center)
} else {
Image("icon_rcxinhua_defaultselected")
.resizable().frame(width: 20, height: 20, alignment: .center)
}
}
}
}
单向数据流
用户操作导致@State变量发生了改变,
@State变量改变导致使用了@State变量的UI视图就会自动更新
继续等待用户操作触发@State变量发生变化
 

UIKit控件与SwiftUI中控件的转换
UIKit转SwiftUI
通过UIViewRepresentable协议将UIView包装成SwifUI的View来使用。
struct MapView: UIViewRepresentable {
let view: UIView = UIView()
func makeUIView(context: Context) -> some UIView {
return view
}
func updateUIView(_ uiView: UIViewType, context: Context) {
view.backgroundColor = .red
}
}
SwiftUI转UIKit
通过UIHostingController将SwiftUI包装成UIView
UIHostingController(rootView: ContentView())
Model模型定义
List,ForEach等要求被循环的每个元素都要有一个唯一的标识
这样数据变更时,可以迅速定位刷新对应的UI,提高性能
所以,元素要遵循Identifiable协议(实现id协议)
struct Landmark: Identifiable {
var id = UUID()
let name: String
}
Demo地址
https://github.com/zhfei/SwiftBasicKnowledge
 
 
参考文章
https://www.jianshu.com/p/0f7215591b08
https://zhuanlan.zhihu.com/p/436779033
 
 

SwiftUI的认识与使用的更多相关文章

  1. SwiftUI 官方教程(八)

    8. 动态生成预览 接下来,我们会在 LandmarkList_Previews 中添加代码以在不同的设备尺寸上渲染列表.默认情况下,预览会以当前的 scheme 中设备的大小进行渲染.我们可以通过调 ...

  2. SwiftUI 官方教程(七)

    7. 给子 View 传递数据 LandmarkDetail 现在依然使用硬编码的数据来显示地标.像 LandmarkRow 一样,LandmarkDetail 类型和它组合的其他 view 都需要一 ...

  3. SwiftUI 官方教程(六)

    6. 在列表和详情之间设置导航 虽然列表已经能显示了,但是我们还不能通过点击单个地标来查看地标详情页面.SwiftUI教程 把 list 嵌入一个 NavigationView 中,并把每个 row  ...

  4. SwiftUI 官方教程(五)

    SwiftUI官方教程(五) 5. 同时使用 UIKit 和 SwiftUI 至此,我们已准备好创建 map view 了,接下来使用 MapKit 中的 MKMapView 类来渲染地图. 在 Sw ...

  5. SwiftUI 官方教程(四)

    SwiftUI 官方教程(四) 4. 自定义 Image View 搞定名称和位置 view 后,我们来给地标添加图片. 这不需要添加很多代码,只需要创建一个自定义 view,然后给图片加上遮罩.边框 ...

  6. SwiftUI 官方教程(三)

    3. 用 Stacks 组合 View 在上一节创建标题 view 后,我们来添加 text view,它用来显示地标的详细信息,比如公园的名称和所在的州. 在创建 SwiftUI view 时,我们 ...

  7. SwiftUI 官方教程(二)

    SwiftUI 官方教程(二) 2. 自定义 Text View 为了自定义 view 的显示,我们可以自己更改代码,或者使用 inspector 来帮助我们编写代码. 在构建 Landmarks 的 ...

  8. SwiftUI 官方教程(一)

    完整中文教程及代码请查看 https://github.com/WillieWangWei/SwiftUI-Tutorials   创建和组合 View 此部分将指引你构建一个发现和分享您喜爱地方的 ...

  9. SwiftUI 官方教程

    SwiftUI 官方教程 完整中文教程及代码请查看 https://github.com/WillieWangWei/SwiftUI-Tutorials   SwiftUI 官方教程 SwiftUI ...

  10. SwiftUI学习(一)

    总览 如果你想要入门 SwiftUI 的使用,那 Apple 这次给出的官方教程绝对给力.这个教程提供了非常详尽的步骤和说明,网页的交互也是一流,是觉得值得看和动手学习的参考. 不过,SwiftUI ...

随机推荐

  1. 2022-04-03:k8s安装srs,yaml如何写?

    2022-04-03:k8s安装srs,yaml如何写? 答案2022-04-03: yaml如下: apiVersion: apps/v1 kind: Deployment metadata: la ...

  2. 2021-12-16:给定两个数a和b, 第1轮,把1选择给a或者b, 第2轮,把2选择给a或者b, ... 第i轮,把i选择给a或者b。 想让a和b的值一样大,请问至少需要多少轮? 来自字节跳动。

    2021-12-16:给定两个数a和b, 第1轮,把1选择给a或者b, 第2轮,把2选择给a或者b, - 第i轮,把i选择给a或者b. 想让a和b的值一样大,请问至少需要多少轮? 来自字节跳动. 答案 ...

  3. 2021-11-10:O(1) 时间插入、删除和获取随机元素。实现RandomizedSet 类:RandomizedSet() 初始化 RandomizedSet 对象。bool insert(in

    2021-11-10:O(1) 时间插入.删除和获取随机元素.实现RandomizedSet 类:RandomizedSet() 初始化 RandomizedSet 对象.bool insert(in ...

  4. Hugging News #0512: 🤗 Transformers、🧨 Diffusers 更新,AI 游戏是下个新热点吗

    每一周,我们的同事都会向社区的成员们发布一些关于 Hugging Face 相关的更新,包括我们的产品和平台更新.社区活动.学习资源和内容更新.开源库和模型更新等,我们将其称之为「Hugging Ne ...

  5. vue全家桶进阶之路6:Vue的安装以及js引入

    1.安装 注意:Vue 不支持 IE8 及以下版本 创建一个文件夹用于下载引入Vue D:\BaiduSyncdisk\vue2 按照最新版本的Vue npm install vue 创建完成后便可以 ...

  6. Element-DatePicker的宽度

    Element如何修改DatePicker的宽度 方法/步骤 1 打开一个vue文件,添加DatePicker日期选择器组件,设置默认日期为null.如图 2 在组件上添加style样式属性,设置wi ...

  7. < Python全景系列-3 > Python控制流程盘点及高级用法、神秘技巧大揭秘!

    欢迎来到我们的系列博客<Python全景系列>!在这个系列中,我们将带领你从Python的基础知识开始,一步步深入到高级话题,帮助你掌握这门强大而灵活的编程语法.无论你是编程新手,还是有一 ...

  8. 牧云 • 主机管理助手|正式开放应用市场,梦幻联动雷池WAF等多款开源软件

    0x00 前言 上个月,我司长亭开源了雷池WAF,不到三天就吸引了超过上千个师傅使用,几个交流群里,师傅们讨论的热火朝天,其中两个话题引起了我们牧云 • 主机管理助手 ( Collie ) 团队的关注 ...

  9. [音视频处理] FFmpeg使用指北1-视频解码

    本文将详细介绍如何使用ffmpeg 4.4在C++中解码多种格式的媒体文件,这些媒体文件可以是视频.视频流.图片,或是桌面截屏或USB摄像头的实时图片.解码文件后,还将每帧图片转换为OpenCV的Ma ...

  10. 马拉车(manacher) & 回文自动机(PAM)

    补充,PAM 的 a[0]=-1,这一点我每次写都要忘记. 读了徐安矣2023年集训队论文写的,对于差分性质和习题,我会在理解清楚之后再补充.本篇博客仅讨论前两种算法. 首先,马拉车和回文自动机都是处 ...