My Initial Impressions of the SwiftUI World -- UI 篇

SwiftUI 是一个声明式的 UI 开发方式,在这之前我们先看看声明式和指令式开发。

指令式 & 声明式 简单了解

指令式编程:通过一些组合语句例如 运算语句、条件语句、循环语句逐条指示计算机如何工作,为了更好的理解我们来看下这个例子:

ini 复制代码
struct Student {
let name: String
let score: Int
}

let zhangsan = Student(name: "zhangsan", score: 100)
let lisi = Student(name: "lisi", score: 60)
let students = [zhangsan, lisi]
我们如果想要知道分数最高的学生 如下:
var best: (Student, Int)?
for student in students {
   if let tempBest = best {
       if tempBest.1 < student.score {
           best = (student, student.score)
          } else {
                best = (student, student.score)
            }
    }
 }

那么如果我们想知道了这段代码具体是什么含义,必须要清楚的知道每一行指令具体做了什么,这样对于开发人员的要求非常高,并且代码越多隐藏的问题也会越多。

声明式开发正好和这个是对立的,声明式更像是我们要告诉计算机要做什么,例如我们平时使用的高阶函数,我们不用去关心过程,例如上述我们找到成绩最好的学生

ini 复制代码
let best = students.sorted{$0.score > $1.score}.first

我们只需要知道这段代码结果是什么。

SwiftUI中,用户界面是严格被数据驱动的,在运行时,我们只能通过修改数据来修改界面,不能直接对界面进行调整和操作,下面我们会有单独文章介绍,这里我们先简单看看声明式UI

UI 都是通过 View 来呈现的,我们写个简单的 hello SwiftUI

swift 复制代码
struct TestUI: View {
    var body: some View {
        Text("hello Swift UI")
        Button("test") {
            print("test")
        }
    }
}

这段代码是可以让我们来实时的看到UI 我们在body中修改可以实时看到效果
struct TestUI_Previews: PreviewProvider {
    static var previews: some View {
        TestUI()
    }
}

在预览栏中我们应该可以实时看到一个界面了

UI Modifier

上述代码你是不是会想我们平时写界面会控制一些label的属性,颜色、字体颜色等,这样不得不引入到Modifier(个人比较喜欢swift的命名方式,简单、语义准确、容易理解), 下面我们通过例子来看看Modifier对text的影响

这些都是 View 的 Modifier,当然还有很多可以看官方文档,从图中可以发现,红色框中和蓝色框中的modifier 是不同的,像蓝色框里这种 font, 字体颜色对顺序要求不高,他们是对 Text 本身的属性修改,对布局也不会产生影响,但是红色框中的pading, background 是对 View 的 extension,对顺序有很高的要求,他们是对 View 进行包装并且返回的 View 的封装类, 可以对比下 橘色框和绿色框的pading。

UI 基本布局

通过上述学习我们了解到 UI 是通过 View 来呈现的,接下来通过例子我们先看看 Swift 里 View 的封装

示例需求: 布局一个 9 宫格的数字展示 从 1-9

1、先看展示部分 最简单的写法如下:

作为有追求的技术人员,一定会想抽象这段代码,恰好小编也对代码有追求的,我们先来对 Text 进行抽象成为一个通用的 view

less 复制代码
struct SudokuItemLabel: View {

    var fontSize: CGFloat = 30 //提供默认值
    var title: String
    var size: CGSize
    var backGroundColor: Color
    var foregroundColor: Color
    var body: some View {
        Text(title)
            .font(.system(size: fontSize))
            .foregroundColor(foregroundColor)
            .background(backGroundColor)
            .frame(width: size.width, height: size.height)
    }
}

然后使用同样的方式对横向进行封装,既然横向是一个同样的逻辑,必然牵扯要动态使用 model 来读取数据,我们先创建一个 item 作为每个数字的数据源

arduino 复制代码
enum SudokuItem {
    case digit(Int)
}

extension SudokuItem: Hashable {
    var title: String {
        switch self {
            case .digit(let value):
                return String(value)
        }
    }

    var size: CGSize {
        let width = floor((UIScreen.main.bounds.size.width - 20 - 3 * 6) / 4)
        if case .digit(let value) = self, value == 0 {
           return CGSize(width: width * 2, height: 88)
        }
        return CGSize(width: width, height: 88)
    }
}

在对横向 UI 进行封装如下:

less 复制代码
struct SudokuItemRow: View {
    let items: [SudokuItem]

    var body: some View {
        HStack {
            ForEach(items, id:\.self) {item in
                SudokuItemLabel(title: item.title, size: item.size)
            }
        }
    }
}

再来看下ContentView的代码

是不是非常简洁了,其实封装思想、设计原则都是相同的,只不过 UI 是通过 View 来呈现。

希望这段代码可以帮助你快速的入门 SwiftUI, 更多知识可以参考官方文档

关于数据驱动 UI 变化的文章,请看我的下篇文章

juejin.cn/creator/con...

相关推荐
Keya20 小时前
lipo 命令行指南
ios·xcode·swift
zhangmeng20 小时前
SwiftUI中如何实现子视图向父视图传递数据?
ios·swiftui·swift
Saafo20 小时前
迁移至 Swift Actors
ios·swift
杂雾无尘2 天前
告别构建错误, iOS 开发架构难题全面解析, 避免 CPU 架构陷阱
ios·swift·客户端
大熊猫侯佩2 天前
探秘 WWDC 25 全新 #Playground 宏:提升 Swift 开发效率的超级神器
xcode·swift·wwdc
移动端小伙伴3 天前
10.推送的扩展能力 — 打造安全的通知体验
swift
移动端小伙伴3 天前
推送的扩展能力 — 打造个性化的通知体验
swift
移动端小伙伴3 天前
远程推送(Remote Push Notification)
swift
移动端小伙伴3 天前
本地通知的精准控制三角:时间、位置、情境
swift
移动端小伙伴3 天前
本地通知内容深度解析 — 打造丰富的通知体验
swift