SwiftUI Introspect
注意
SwiftUIIntrospect
是一个全新的模块,基于原始的 Introspect
模块,改进了稳定性、可预测性和易用性。
这两个模块目前都存放在这个仓库中,但最终计划是随着 1.0 版本的发布,废弃 Introspect
并使用 SwiftUIIntrospect
。
虽然 Introspect
支持 Swift 5.5 或更高版本,但 SwiftUIIntrospect
需要 Swift 5.7 或更高版本,因为使用了更现代的语言特性,这有助于实现上述改进。
SwiftUIIntrospect 允许您获取 SwiftUI 视图的底层 UIKit 或 AppKit 元素。
例如,使用 SwiftUIIntrospect,您可以访问 UITableView
来修改分隔符,或访问 UINavigationController
来自定义标签栏。
它是如何工作的
SwiftUIIntrospect 通过在所选视图上方添加一个不可见的 IntrospectionView
,以及下方添加一个不可见的“锚点”视图,然后在两者之间通过 UIKit/AppKit 视图层次结构查找相关视图来工作。
例如,当检查 ScrollView
...
ScrollView {
Text("Item 1")
}
.introspect(.scrollView, on: .iOS(.v13, .v14, .v15, .v16, .v17)) { scrollView in
// do something with UIScrollView
}
...
- 它将
- 将
IntrospectionView
设置为TextField
的覆盖层。 - 将
IntrospectionAnchorView
设置为TextField
的背景。
遍历两个视图之间的所有子视图,直到找到一个 UIScrollView
实例(如果有的话)。
警告
默认情况下,.introspect
直接在其 接收者 上工作。这意味着从您要分析的观点内部调用 .introspect
不会产生任何效果。这与原始的 Introspect
模块不同,其中一些视图会隐式允许从内部进行反射。这主要是因为大多数时候直接反射视图更为稳定和可预测,但有时这对于库开发者来说是不可能或太不灵活的。您 可以 使用 SwiftUIIntrospect
反射一个 祖先,但您必须显式选择这个行为,通过重写反射 scope
ScrollView {
Text("Item 1")
.introspect(.scrollView, on: .iOS(.v13, .v14, .v15, .v16, .v17), scope: .ancestor) { scrollView in
// do something with UIScrollView
}
}
在生产环境中使用
SwiftUIIntrospect
意图在生产中使用。它不使用任何私有 API。它仅使用公开方法检查视图层次结构。该库在检查视图层次结构上采取了一种保护性的方法:没有对元素布局的硬性假设,没有对 UIKit/AppKit 类的强制转换,如果找不到 UIKit/AppKit 视图,则简单地忽略 .introspect
修饰符。
安装
Swift 包管理器
let package = Package(
dependencies: [
.package(url: "https://github.com/siteline/swiftui-introspect", from: "0.11.0"),
],
targets: [
.target(name: <#Target Name#>, dependencies: [
.product(name: "SwiftUIIntrospect", package: "swiftui-introspect"),
]),
]
)
CocoaPods
pod 'SwiftUIIntrospect'
自省
已实现
按钮
颜色选择器
日期选择器
日期选择器
配合.compact
样式日期选择器
配合.field
样式日期选择器
配合.graphical
样式日期选择器
配合.stepperField
样式日期选择器
配合.wheel
样式表单
表单
配合.grouped
样式.fullScreenCover
列表
列表
配合.bordered
样式列表
配合.grouped
样式列表
配合.insetGrouped
样式列表
配合.inset
样式列表
配合.sidebar
样式列表单元格
地图
导航分割视图
导航栈
导航视图
配合.columns
样式导航视图
配合.stack
样式页码控件
选择器
配合.menu
样式选择器
配合.segmented
样式选择器
配合.wheel
样式.弹出视图
进度视图
配合.circular
样式进度视图
配合.linear
样式滚动视图
.可搜索的
安全字段
.表单
使用Apple ID登录按钮
滑块
步进器
表格
标签视图
标签视图
配合.page
样式文本编辑器
文本字段
文本字段
配合.vertical
轴开关
开关
配合按钮
样式开关
配合复选框
样式开关
配合开关
样式视频播放器
视图
视图控制器
窗口
缺少一个元素?请创建一个issue。作为临时解决方案,您可以实现您自己的可自省视图类型。
不能实现
SwiftUI | 受影响的框架 | 为什么 |
---|---|---|
文本 | UIKit, AppKit | 不是UILabel / NSLabel |
图像 | UIKit, AppKit | 不是UIImageView / NSImageView |
按钮 | UIKit | 不是一个UIButton |
示例
列表
List {
Text("Item")
}
.introspect(.list, on: .iOS(.v13, .v14, .v15)) { tableView in
tableView.backgroundView = UIView()
tableView.backgroundColor = .cyan
}
.introspect(.list, on: .iOS(.v16, .v17)) { collectionView in
collectionView.backgroundView = UIView()
collectionView.subviews.dropFirst(1).first?.backgroundColor = .cyan
}
滚动视图(ScrollView)
ScrollView {
Text("Item")
}
.introspect(.scrollView, on: .iOS(.v13, .v14, .v15, .v16, .v17)) { scrollView in
scrollView.backgroundColor = .red
}
导航视图(NavigationView)
NavigationView {
Text("Item")
}
.navigationViewStyle(.stack)
.introspect(.navigationView(style: .stack), on: .iOS(.v13, .v14, .v15, .v16, .v17)) { navigationController in
navigationController.navigationBar.backgroundColor = .cyan
}
文本字段(TextField)
TextField("Text Field", text: <#Binding<String>#>)
.introspect(.textField, on: .iOS(.v13, .v14, .v15, .v16, .v17)) { textField in
textField.backgroundColor = .red
}
实现您自己的选择器
缺少一个元素? 请创建一个问题。
如果SwiftUIIntrospect不支持您正在寻找的SwiftUI元素,您可以实现自己的选择器。例如,要查找TextField
@_spi(Advanced) import SwiftUIIntrospect
public struct TextFieldType: IntrospectableViewType {}
extension IntrospectableViewType where Self == TextFieldType {
public static var textField: Self { .init() }
}
#if canImport(UIKit)
extension iOSViewVersion<TextFieldType, UITextField> {
public static let v13 = Self(for: .v13)
public static let v14 = Self(for: .v14)
public static let v15 = Self(for: .v15)
public static let v16 = Self(for: .v16)
public static let v17 = Self(for: .v17)
}
extension tvOSViewVersion<TextFieldType, UITextField> {
public static let v13 = Self(for: .v13)
public static let v14 = Self(for: .v14)
public static let v15 = Self(for: .v15)
public static let v16 = Self(for: .v16)
public static let v17 = Self(for: .v17)
}
extension visionOSViewVersion<TextFieldType, UITextField> {
public static let v1 = Self(for: .v1)
}
#elseif canImport(AppKit)
extension macOSViewVersion<TextFieldType, NSTextField> {
public static let v10_15 = Self(for: .v10_15)
public static let v11 = Self(for: .v11)
public static let v12 = Self(for: .v12)
public static let v13 = Self(for: .v13)
public static let v14 = Self(for: .v14)
}
#endif
发布
-
更新变更日志与新版本
-
以'提升到X.Y.Z'提交PR并合并它
-
标记新版本
$ git tag X.Y.Z $ git push origin --tags