GithubHelp home page GithubHelp logo

leonboe1 / swiftui-introspect Goto Github PK

View Code? Open in Web Editor NEW

This project forked from siteline/swiftui-introspect

0.0 0.0 0.0 467 KB

Introspect underlying UIKit/AppKit components from SwiftUI

License: MIT License

Ruby 1.42% Swift 98.58%

swiftui-introspect's Introduction

SwiftUI Introspect

CI Status Badge Platform Compatibility Badge

Note

SwiftUIIntrospect is an all-new module based off the original Introspect module that improves on stability, predictability, and ergonomics.

Both modules currently live together under this repo, but the plan is to ultimately obsolete Introspect in favor of SwiftUIIntrospect as part of a 1.0 release.

While Introspect supports Swift 5.5 or higher, SwiftUIIntrospect requires Swift 5.7 or higher due to the use of more recent language features which partially enable the aforementioned improvements over the original.

SwiftUIIntrospect allows you to get the underlying UIKit or AppKit element of a SwiftUI view.

For instance, with SwiftUIIntrospect you can access UITableView to modify separators, or UINavigationController to customize the tab bar.

How it works

SwiftUIIntrospect works by adding an invisible IntrospectionView on top of the selected view, and an invisible "anchor" view underneath it, then looking through the UIKit/AppKit view hierarchy between the two to find the relevant view.

For instance, when introspecting a ScrollView...

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

... it will:

  • Add IntrospectionView as an overlay of TextField
  • Add IntrospectionAnchorView as the background of TextField.
  • Traverse through all the subviews between both views until a UIScrollView instance (if any) is found.

Warning

Although this introspection method is very solid and unlikely to break in itself, future OS releases require explicit opt-in for introspection (.iOS(.vXYZ)), given potential differences in underlying UIKit/AppKit view types between major OS versions.

By default, .introspect works directly on its receiver. This means calling .introspect from inside the view you're trying to introspect won't have any effect. This is different to the original Introspect module in which some views would implicitly allow introspection from within. This is because most of the time it's more stable and predictable to introspect views directly, but there are times when it's not possible or simply too inflexible for library developers. You can introspect an ancestor with SwiftUIIntrospect, but you must opt into this explicitly by overriding the introspection scope:

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

Usage in production

SwiftUIIntrospect is meant to be used in production. It does not use any private API. It only inspects the view hierarchy using publicly available methods. The library takes a defensive approach to inspecting the view hierarchy: there is no hard assumption that elements are laid out a certain way, there is no force-cast to UIKit/AppKit classes, and the .introspect modifier is simply ignored if UIKit/AppKit views cannot be found.

Install

Swift Package Manager

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'

Introspection

Implemented

Missing an element? Please create an issue. As a temporary solution, you can implement your own introspectable view type.

Cannot implement

SwiftUI Affected Frameworks Why
Text UIKit, AppKit Not a UILabel / NSLabel
Image UIKit, AppKit Not a UIImageView / NSImageView
Button UIKit Not a UIButton

Examples

List

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
    }

Implement your own selector

Missing an element? Please create an issue.

In case SwiftUIIntrospect doesn't support the SwiftUI element that you're looking for, you can implement your own selector. For example, to introspect a 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

Releasing

  1. Update changelog with new version

  2. PR as 'Bump to X.Y.Z' and merge it

  3. Tag new version:

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

swiftui-introspect's People

Contributors

davdroman avatar ldiqual avatar jannthomas avatar renovate[bot] avatar splittydev avatar joelpoloney avatar leonboe1 avatar aaryankotharii avatar orospakr avatar chrismaddern avatar ethanbonin avatar crayment avatar dmonagle avatar grdsdev avatar iansampson avatar jevonmao avatar kkebo avatar lechium avatar krzyzanowskim avatar michaeljberk avatar nuplay avatar paescebu avatar steipete avatar kaishin avatar rzulkoski avatar simba909 avatar vukrado avatar dependabot[bot] avatar ryohey avatar okmyself avatar

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.