审查 0.12.0

审查 0.12.0

Lois Di QualLois Di QualDavid Roman维护。



审查 0.12.0

  • Lois Di Qual

SwiftUI审查

CI Status Badge Platform Compatibility Badge

注意

SwiftUIIntrospect是一个基于原始审查模块的所有新的模块,它在稳定性、可预测性和人体工程学方面进行了改进。

这两个模块目前在同一仓库下共存,但计划最终废弃审查模块,以SwiftUI审查作为1.0版的一部分。

虽然审查支持Swift 5.5或更高版本,但SwiftUI审查需要Swift 5.7或更高版本,这是因为它使用了更现代的语言特性,这部分上实现了上述改进。

SwiftUI审查允许您获取SwiftUI视图的底层的UIKit或AppKit元素。

例如,使用SwiftUI审查,您可以访问UITableView来修改分隔符,或者访问UINavigationController来自定义标签栏。

它如何工作

SwiftUI审查通过在所选视图上添加一个不可见的IntrospectionView,在其下方添加一个不可见的“锚点”视图,然后在这两个视图之间的UIKit/AppKit视图层次结构中查找相关视图来实现。

例如,在审查ScrollView时...

ScrollView {
    Text("Item 1")
}
.introspect(.scrollView, on: .iOS(.v13, .v14, .v15, .v16, .v17)) { scrollView in
    // do something with UIScrollView
}

...

  • 它将向TextField添加IntrospectionView作为叠加层
  • IntrospectionAnchorView作为TextField的背景。
  • 遍历两个视图之间的所有子视图,直到找到UIScrollView实例(如果有的话)。

注意

尽管这种检查方法非常稳定且不会自身崩溃,但鉴于大型操作系统版本之间的底层 UIKit/AppKit 视图类型可能存在差异,未来操作系统版本需要显式启用检查(.iOS(.vXYZ))。

默认情况下,.introspect 直接作用于其 接收器。这意味着在您尝试检查的视图内部调用 .introspect 不会产生任何效果。这与原始 Introspect 模块不同,其中一些视图从内部隐式允许检查。这是因为在大多数情况下,直接检查视图更为稳定和可预测,但有时这可能不适合库开发者。您可以使用 SwiftUIIntrospect 检查 祖先,但您必须明确通过重写检查 作用域 来启用此功能。

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.10.0"),
    ],
    targets: [
        .target(name: <#Target Name#>, dependencies: [
            .product(name: "SwiftUIIntrospect", package: "swiftui-introspect"),
        ]),
    ]
)

CocoaPods

pod 'SwiftUIIntrospect'

自省

实现

缺少一个元素?创建一个问题。作为一个临时解决方案,您可以实现自己的可自省视图类型

无法实现

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 {
    Text("Item")
}
.introspect(.scrollView, on: .iOS(.v13, .v14, .v15, .v16, .v17)) { scrollView in
    scrollView.backgroundColor = .red
}

导航视图

NavigationView {
    Text("Item")
}
.navigationViewStyle(.stack)
.introspect(.navigationView(style: .stack), on: .iOS(.v13, .v14, .v15, .v16, .v17)) { navigationController in
    navigationController.navigationBar.backgroundColor = .cyan
}

文本框

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)
}
#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

发布

  1. 更新变更日志以包含新版本

  2. 将PR作为'Bump to X.Y.Z'提交并合并

  3. 标记新版本

    $ git tag X.Y.Z
    $ git push origin --tags