iOS 实现微信读书的仿真翻页
先看效果 仿真翻页效果: 普通翻页效果: 实现方案 iOS 中实现翻页效果比较简单,直接使用系统提供的 UIPageViewController 即可做到。 UIPageViewController
这是一位独立开发者跨上双平台之路的完整记录:从 iOS 的舒适区,到 Android 的碎片化现实;从协作模式、交互差异,到商店后台、支付体系和中国安卓生态的真实挑战。产品在变,他的理解和心态也在变。或许能让仍只在苹果生态中的你看到另一条可能的路径。
本文帮助有Swift基础的同学,快速入门SwiftUI,基于cursour整理
主要分为四个部分:
some 表示"某个特定的类型,该类型遵循某个协议"。它的特点是:
some vs any 核心区别
| 特性 | some | any |
|---|---|---|
| 类型确定 | 编译时确定,固定不变 | 运行时可变 |
| 性能 | 快(静态派发) | 慢(动态派发,有装箱开销) |
| 类型一致性 | 必须始终返回同一类型 | 可以返回不同类型 |
| 引入版本 | Swift 5.1 | Swift 5.6 |
| 使用场景 | 返回类型、属性 | 需要类型灵活性时 |
// some - 固定的具体类型
func makeSomeView() -> some View {
Text("Hello") // 每次调用都返回 Text 类型
}
// any - 可以是任何符合协议的类型
func makeAnyView(condition: Bool) -> any View {
if condition {
return Text("Hello") // 这次返回 Text
} else {
return Image("icon") // 下次可能返回 Image
}
}
| 属性包装器 | 用途 | 拥有数据 | 数据类型 | 典型场景 |
|---|---|---|---|---|
| @State | 当前View状态处理 | ✅ 是 | 值类型 | 简单的 UI 状态 |
| @Binding | 父子View间状态传递 | ❌ 否 | 任意 | 子视图修改父状态 |
| @StateObject | 当前View引用对象,对象的生命周期在当前View | ✅ 是 | 引用类型 | 视图的 ViewModel |
| @ObservedObject | 父子View间对象状态传递,对象在父View | ❌ 否 | 引用类型 | 传入的对象 |
| @EnvironmentObject | 跨View间状态传递 | ❌ 否 | 引用类型 | 全局共享数据 |
| @Environment | 系统环境 | ❌ 否 | 系统提供 | 系统设置和服务 |
1. @State - 私有状态 用于管理视图内部的简单值类型状态。
struct CounterView: View {
@State private var count = 0
@State private var isOn = false
@State private var name = ""
var body: some View {
VStack {
Text("计数: \(count)")
Button("增加") {
count += 1 // 修改会触发视图刷新
}
Toggle("开关", isOn: $isOn)
TextField("姓名", text: $name)
}
}
}
特点:
2. @Binding - 双向绑定
创建对父视图状态的双向绑定。
struct ParentView: View {
@State private var isPresented = false
var body: some View {
VStack {
Button("显示") {
isPresented = true
}
// 传递绑定
ChildView(isPresented: $isPresented)
}
}
}
struct ChildView: View {
@Binding var isPresented: Bool // 绑定到父视图的状态
var body: some View {
Toggle("显示状态", isOn: $isPresented)
// 修改会同步到父视图
}
}
特点:
3. @StateObject - 引用类型的拥有者
用于创建和拥有 ObservableObject 实例
// 1. 创建可观察对象
class ViewModel: ObservableObject {
@Published var items: [String] = []
@Published var isLoading = false
func loadData() {
isLoading = true
// 加载数据...
items = ["Item 1", "Item 2"]
isLoading = false
}
}
// 2. 在视图中使用
struct ContentView: View {
@StateObject private var viewModel = ViewModel()
var body: some View {
List(viewModel.items, id: \.self) { item in
Text(item)
}
.onAppear {
viewModel.loadData()
}
}
}
3. @ObservedObject - 引用类型的观察者
用于观察已存在的 ObservableObject(不拥有)。
class ViewModel: ObservableObject {
@Published var count = 0
}
struct ParentView: View {
@StateObject private var viewModel = ViewModel() // 拥有
var body: some View {
ChildView(viewModel: viewModel) // 传递
}
}
struct ChildView: View {
@ObservedObject var viewModel: ViewModel // 观察(不拥有)
var body: some View {
VStack {
Text("计数: \(viewModel.count)")
Button("增加") {
viewModel.count += 1
}
}
}
}
特点:
5. @EnvironmentObject - 环境对象 在视图层级中共享对象,无需逐层传递。
class UserSettings: ObservableObject {
@Published var username = "Guest"
@Published var isDarkMode = false
}
@main
struct MyApp: App {
@StateObject private var settings = UserSettings()
var body: some Scene {
WindowGroup {
ContentView()
.environmentObject(settings) // 注入
}
}
}
struct ContentView: View {
@EnvironmentObject var settings: UserSettings // 自动获取
var body: some View {
VStack {
Text("用户: \(settings.username)")
SettingsView() // 子视图也能访问
}
}
}
struct SettingsView: View {
@EnvironmentObject var settings: UserSettings // 直接访问
var body: some View {
Toggle("深色模式", isOn: $settings.isDarkMode)
}
}
特点:
6. @Environment - 系统环境值
访问 SwiftUI 提供的系统环境值。
struct MyView: View {
@Environment(\.colorScheme) var colorScheme // 深色/浅色模式
@Environment(\.dismiss) var dismiss // 关闭动作
@Environment(\.horizontalSizeClass) var sizeClass // 尺寸类别
var body: some View {
VStack {
Text("当前模式: \(colorScheme == .dark ? "深色" : "浅色")")
Button("关闭") {
dismiss()
}
}
}
}
常用环境值:
最佳实践
// 1. 简单值用 @State
@State private var count = 0
// 2. 创建对象用 @StateObject
@StateObject private var viewModel = ViewModel()
// 3. 传递对象用 @ObservedObject
@ObservedObject var viewModel: ViewModel
// 4. 传递绑定用 @Binding
@Binding var isPresented: Bool
// 5. 全局共享用 @EnvironmentObject
@EnvironmentObject var settings: AppSettings