oh-my-docs

Summary for developers


Project maintained by italkso Hosted on GitHub Pages — Theme by mattgraham

SwiftUI

1. 概述

import SwiftUI

struct SwiftUIView: View {
    var body: some View {
        Text("Hello World")
            .font(.headline)
            .foregroundColor(.white)
            .padding()
            .background(Color.primary)
            .cornerRadius(8.0)
    }
}

1.1 View 和 Modifier

ViewModifier **是声明式 UI 框架 **SwiftUI 的核心 。比如,代码Text("Hello World") .font(.headline),表示Text View被字体修改器 .font(.headline) 修改。界面功能由 Swift 配合框架实现,比如播放歌曲、点击按钮后触发付款流程、复制到剪贴板等。

1.2 SwiftUI 应用程序的组成

1.3 数据流动

将与特定 View 相关的数据封装进 View 的视图结构中,可以使用达到「复用」Views 的目的。

Manage Mutable Values as State

 @State private var isSearch: Bool = false

你可以使用属性包装器 @State声明一个变量,用来存储视图中可能被修改的数据。声明为 @State 的变量就是状态属性(state properties),仅用于管理那些会影响到 UI 的瞬时状态(transient state ),比如按钮的高亮状态、过滤设置或者当前选择的列表项。你不应该将状态属性用作数据的持久存储(persistent storage)。

Share Access to State with Bindings

A diagram showing state stored in one view, shared with another view through

为了保证在多个Views 中共享数据的一致性,要遵循唯一真值原则(Single Source of Truth),这是数据流动中的重要思想。用户无论处在应用程序的哪一个视图结构中,其信息只应该被存储一次。因此,在子视图中应该使用 @Binding 与父视图中,即那些声明为 @State 的变量进行绑定。这样,多个视图之间就可以共享对状态属性的控制。

@Binding var isSearch: Bool

注意,绑定(binding)只是对状态属性的引用,@Binding 变量本身并不拥有一份存储。

使用美元符号 $作为前缀可以传递变化,如$isSearch

Animate State Transitions

视图(View)状态发生变化时,SwiftUI 会立即更新该状态变化影响到的视图。你可以添加平滑的视觉过渡,方法是调用withAnimation(_:_:) 并将修改状态的代码放入该函数的尾随闭包(trailing closure)中。如果你仅仅是想针对某个特定的页面有过渡效果,使用animation(_:) 视图修改器就好了。

2. UI 与交互层面

常用视图

// 文本视图

@state var username = ""
@state var password = ""
@State var textInput = ""

var body: some View {
    Text("Hello, World!")
	Label("显示文字", systemImage: "SF Symbol 图标名称")
	TextField("占位文字", text: $username)
    SecureField("占位文字", text: $password)
}

视图运作原理

在 SwiftUI 中,由每个视图自行索要大小。当视图中内容大小明确时,视图根据自身需求索要空间。当视图本身内容大小不明确时,该视图会索要全部剩余空间。

操作系统会告知应用其视图可用总空间的大小 (Proposed Size),该大小会层层传递给子级视图,子级视图会根据自身需求,用两种方式索要大小 (Claimed Size)。

SwiftUI 会将被索要的大小从总空间中剔除,并将剩余空间继续传给其它子级视图。在视图大小的传递过程中,SwiftUI 的作用是尽量协调并尊重每个视图索要的区域。空间不够时,则 SwiftUI 会在自身可控范围内适当压缩间距大小。如果空间还不够,则会协调视图相互妥协。

视图内布局

自定义修改器

import SwiftUI

struct SignInView: View {
    @State var username = ""
    @State var password = ""
    
    var body: some View {
        VStack {
            TextField("Username", text: $username) .inputFieldStyle()          
            SecureField("Password", text: $password).inputFieldStyle()
        }
    }
}

//  Create custom modifier - Step1
struct InputFieldModifirer: ViewModifier {
    func body(content: Content) -> some View {
        content
            .font(.body)
            .foregroundColor(.primary)
            .textFieldStyle(RoundedBorderTextFieldStyle())
            .font(.headline)
            .frame(width: UIScreen.main.bounds.width / 1.1)
            .padding()
            .shadow(color: .secondary, radius: 5, x: 1, y: 5)
    }
}

// Create custom modifier - Step2
extension View {
    func inputFieldStyle() -> some View {
        self.modifier(InputFieldModifirer())
    }
}

4. 状态和数据流动(State & Data Flow)

SwiftUI provides tools, like state variables and bindings, for connecting your app’s data to the user interface. These tools help you maintain a single source of truth for every piece of data in your app.

A diagram showing how SwiftUI responds to external events and user inputs by

Image from Apple Developer

数据流动(Data Flow) 指应用程序中数据的传递方式。

「接收用户输入的数据」、「改变数据状态来更新界面、「渲染新内容」等由 SwiftUI 负责,开发者只需要使用由符号 @ 表示的属性包装器(Property Wrapper)说明想要执行的操作。

@State、@Binding 和@Environment 是与数据流动有关的几个常见属性包装器。它们主要负责不同视图间的信息传递,视图与数据之间的沟通。

6. 数据存储

数据存储 (Data Persistence)表示本地或者云端存储。

FileManager

使用 FileManager 访问设备的本地存储空间,并将数据以 JSON 文件的形式储存。

7. UIFeedbackGenerator

反馈生成器 UIFeedbackGenerator 包含三个变种,分别是 UINotificationFeedbackGeneratorUIImpactFeedbackGeneratorUISelectionFeedbackGenerator 用于生成基础的震动反馈。

Reference

[1] https://developer.apple.com/documentation/swiftui/state-and-data-flow

[2] https://developer.apple.com/documentation/SwiftUI/Managing-User-Interface-State