SwiftUI 教程

SwiftUI 主页 SwiftUI 概览 SwiftUI 与 UIkit

SwiftUI 环境

SwiftUI 安装和环境配置 SwiftUI 基本组件 SwiftUI 构建第一个应用程序

SwiftUI 视图

SwiftUI 视图 SwiftUI 自定义文本视图 SwiftUI 自定义图像视图 SwiftUI 堆栈

SwiftUI 绘制形状

SwiftUI 形状 SwiftUI 绘制线条 SwiftUI 绘制矩形 SwiftUI 绘制圆角矩形 SwiftUI 绘制三角形 SwiftUI 绘制圆形 SwiftUI 绘制星形 SwiftUI 绘制多边形 SwiftUI 绘制饼图 SwiftUI 使用内置形状

SwiftUI 文本

SwiftUI 文本视图 SwiftUI 文本输入和输出

SwiftUI 颜色

SwiftUI 颜色 SwiftUI 颜色选择器 SwiftUI 渐变 SwiftUI 调整颜色

SwiftUI 效果

SwiftUI 效果 SwiftUI 混合效果 SwiftUI BLur 效果 SwiftUI 阴影效果 SwiftUI 悬停效果

SwiftUI 动画

SwiftUI 动画 SwiftUI 创建动画 SwiftUI 创建显式动画 SwiftUI 多个动画 SwiftUI 过渡 SwiftUI 不对称过渡 SwiftUI 自定义过渡

SwiftUI 图像

SwiftUI 图像 SwiftUI 图像作为背景 SwiftUI 旋转图像 SwiftUI 媒体

SwiftUI 视图布局

SwiftUI 视图布局 SwiftUI 视图大小 SwiftUI 视图间距 SwiftUI 视图填充

SwiftUI UI 控件

SwiftUI UI 控件 SwiftUI 按钮 SwiftUI 复选框 SwiftUI 菜单栏 SwiftUI 工具栏 SwiftUI 搜索栏 SwiftUI 文本字段 SwiftUI 滑块 SwiftUI 切换 SwiftUI 选择器 SwiftUI 菜单

SwiftUI 列表 &表格

SwiftUI 列表 SwiftUI 静态列表 SwiftUI 动态列表 SwiftUI 自定义列表 SwiftUI 表格

SwiftUI 表单

SwiftUI 表单 SwiftUI 在部分中拆分表单

SwiftUI 事件处理

SwiftUI 事件处理 SwiftUI 手势 SwiftUI 剪贴板 SwiftUI 拖放 SwiftUI 焦点 SwiftUI 警报

SwiftUI 杂项

SwiftUI 容器 SwiftUI 导航 SwiftUI 通知 SwiftUI 跨平台 UI SwiftUI 数据 SwiftUI 可访问性

SwiftUI 框架集成

SwiftUI 框架集成 SwiftUI 与 UIKit 交互 SwiftUI 创建 macOS 应用

SwiftUI 有用资源

SwiftUI 有用资源 SwiftUI 讨论


SwiftUI - 数据

在为 Apple 平台开发响应式和交互式应用程序时,数据管理是一个非常重要且关键的部分。众所周知,SwiftUI 使用声明式方式,应用程序的 UI 将根据底层数据自动更新,因此无论何时数据由于某些外部事件或用户操作而发生变化,它都会直接影响界面的各个部分。

因此,数据及其流和状态的管理非常重要。该框架提供了各种工具,例如状态变量和绑定,以将数据连接到应用程序的 UI。这些工具管理数据的来源或数据中发生的任何变化。以下是 SwiftUI 中最常用的数据管理技术 −

  • @State 属性包装器

  • @Binding 属性包装器

  • @ObservedObject 属性包装器

  • @EnvironmentObject 属性包装器

SwiftUI 中的 @State 属性包装器

@State 属性包装器用于读取和写入由 SwiftUI 管理的值。它为我们存储在视图中的给定值类型保存单一来源。它可以通过使用 @State 属性为所有类型的视图创建状态变量,并且每个状态变量都用某个初始值初始化。

因此,当状态变量的值发生变化时,SwiftUI 将自动更新视图中依赖于状态变量值的那些部分。状态变量通常被声明为私有的,这可以防止它们在范围之外使用。

我们可以改变状态属性。如果我们将状态属性传递给子视图,SwiftUI 将在主容器视图中的值发生变化时更新子视图,而子视图不能修改该值。要修改该值,我们需要将其作为绑定传递。我们也可以在 State 中存储 Observable()。

语法

以下是语法 −

@State private var value : Double = 2.3

示例

以下 SwiftUI 程序创建并访问状态变量。在这里,状态管理计数变量的值,每当计数的值发生变化时,视图都会相应更新。

import SwiftUI
struct ContentView: View {
   // State variable
   @State private var count = 0
   var body: some View {
      VStack {
         Text("Counter: \(count)").font(.largeTitle)
         Button("Increment") {
            count += 1
         }
         .frame(width: 100, height: 60)
         .background(.blue)
         .foregroundStyle(.white)
         .font(.headline)         
      }
   }
}
#Preview {
   ContentView()
}

输出

Data

SwiftUI 中的 @Binding 属性包装器

绑定属性包装器在子视图和父视图之间创建双向关系,以便子视图可以轻松读取和写入父视图数据,反之亦然。

在这里,我们可以根据需要随时更新绑定变量,而无需直接将数据存储在其中。要传递绑定属性包装器,我们需要在属性前使用 $。或者我们可以说,我们可以借助绑定属性包装器将状态属性传递给另一个视图。我们还可以使用 @Binding 属性包装器创建绑定属性。

语法

以下是语法−

@Binding var value : Bool

示例

以下 SwiftUI 程序创建绑定属性。在这里,我们将状态变量作为绑定传递并创建了一个绑定变量。

import SwiftUI
struct ContentView: View {   
   // state variable
   @State private var count = 0
   var body: some View {
      VStack {
         Text("Counter: \(count)").font(.largeTitle).border(.black, width: 4)
         
         // Passing count as a binding
         newView(count: $count)
      }
   }
}
struct newView: View {   
   // Binding variable
   @Binding var count: Int
   var body: some View {
      Button("Increase Value") {
         count += 1
      }
      .frame(width: 130, height: 50)
      .background(.brown)
      .foregroundStyle(.white)
      .font(.headline)
   }
}
#Preview {
   ContentView()
}

输出

Data

SwiftUI 中的 @StateObject 和 @ObservedObject 属性包装器

@ObservedObject 属性包装器用于包装可观察对象并观察它们,而 @StateObject 用于创建和管理可观察对象。这两个包装器都需要符合 ObservableObject 协议的对象。

因此,每当可观察对象的值发生修改时,SwiftUI 都会更新与该对象相关的所有视图。它不包含任何默认值或初始值,可以由子视图使用。这里允许子视图更新属性。

语法

以下是语法−

@StateObject private var model = ObservableObject()
@ObservedObject private var model = ObservableObject()

示例

以下 SwiftUI 程序使用 @StateObject 和 @ObservedObject 属性来管理可观察对象。

import SwiftUI
// 创建可观察对象
class Counter: ObservableObject {
   @Published var count = 0
}
struct ContentView: View {
   @StateObject private var counter = Counter()
   var body: some View {
      
      // 将计数器传递给 newView
      newView(myCounter: counter)
   }
}
struct newView: View {   
   // Observing the model
   @ObservedObject var myCounter: Counter
   var body: some View {
      VStack {
         Text("Count: \(myCounter.count)")
            .font(.largeTitle)
            .bold()
            .padding()
         Button("Increment") {
            myCounter.count += 1
         }
         .frame(width: 130, height: 50)
         .background(.brown)
         .foregroundStyle(.white)
         .font(.headline)
      }
   }
}
#Preview {
   ContentView()
}

输出

Data

SwiftUI 中的 @EnvironmentObject 属性包装器

@EnvironmentObject 属性包装器用于在具有可观察对象的所有视图之间共享数据。它共享数据而无需在视图层次结构中明确传递数据。数据在层次结构中的所有视图的公共环境中共享,如果任何视图更新数据,则它将自动更新所有视图。

共享对象必须符合 ObservableObject 协议,并且其属性必须使用 @Published 定义。共享数据必须在视图层次结构的较高级别的 .environmentObject() 中注入,并且可以使用 @EnvironmentObject 由任何视图访问。

语法

以下是语法 −

@EnvironmentObject var mySettings: ObservableObject()

示例

以下 SwiftUI 程序使用 @EnvironmentObject 设置 dark 模式。

import SwiftUI
class Settings: ObservableObject {
   @Published var darkMode: Bool = false
}
struct ContentView: View {
   @StateObject private var newSettings = Settings()
   var body: some View {
      VStack {
         Text("Original View")
            .font(.largeTitle)
            .padding()
         
         // Toggle dark mode
         ToggleView()
         
         // Display dark mode
         DisplayView()
      }
      
      // 在环境对象中传递 newSettings
      .environmentObject(newSettings)
   }
}
struct ToggleView: View {   
   // Accessing the Settings
   @EnvironmentObject var mySettings: Settings
   var body: some View {      
      // Binding darkMode to the toggle
      Toggle("Dark Mode", isOn: $mySettings.darkMode)
         .padding()
         .frame(width: 200, height: 200)
         .background(mySettings.darkMode ? .black : .white)
         .foregroundStyle(mySettings.darkMode ? .white : .black)
   }
}
struct DisplayView: View {
   
   // Access the Settings
   @EnvironmentObject var settings: Settings

   var body: some View {
      Text("Dark Mode is \(settings.darkMode ? "Activated" : "Deactivated")")
         .font(.title)
         .padding()
         .foregroundStyle(settings.darkMode ? .white : .black)
         .background(settings.darkMode ? .black : .white)
   }
}
#Preview {
   ContentView()
}

输出

数据