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...

相关推荐
一丝晨光1 天前
继承、Lambda、Objective-C和Swift
开发语言·macos·ios·objective-c·swift·继承·lambda
KWMax2 天前
RxSwift系列(二)操作符
ios·swift·rxswift
Mamong2 天前
Swift并发笔记
开发语言·ios·swift
小溪彼岸2 天前
【iOS小组件】小组件尺寸及类型适配
swiftui·swift
Adam.com3 天前
#Swift :回调地狱 的解决 —— 通过 task/await 来替代 nested mutiple trailing closure 来进行 回调的解耦
开发语言·swift
Anakki3 天前
【Swift官方文档】7.Swift集合类型
运维·服务器·swift
KeithTsui3 天前
集合论(ZFC)之 联合公理(Axiom of Union)注解
开发语言·其他·算法·binder·swift
東三城4 天前
【ios】---swift开发从入门到放弃
ios·swift
文件夹__iOS7 天前
[SwiftUI 开发] @dynamicCallable 与 callAsFunction:将类型实例作为函数调用
ios·swiftui·swift