Skip to content
Introspect underlying UIKit components from SwiftUI
Swift Ruby Objective-C
Branch: master
Clone or download
Fetching latest commit…
Cannot retrieve the latest commit at this time.
Permalink
Type Name Latest commit message Commit time
Failed to load latest commit information.
.circleci Add CircleCI (#3) Dec 2, 2019
Introspect.xcodeproj Add .introspectViewController() Dec 10, 2019
Introspect.xcworkspace Add TextField Nov 27, 2019
Introspect
IntrospectExamples Add .introspectViewController() Dec 10, 2019
IntrospectTests Add .introspectViewController() Dec 10, 2019
docs
fastlane Add CircleCI (#3) Dec 2, 2019
.gitignore Add diagram Nov 27, 2019
.ruby-version Add TextField Nov 27, 2019
CHANGELOG.md Bump to 0.0.6 Dec 10, 2019
Gemfile Add CircleCI (#3) Dec 2, 2019
Gemfile.lock Add CircleCI (#3) Dec 2, 2019
Introspect.podspec Bump to 0.0.6 Dec 10, 2019
LICENSE Add license + examples Nov 27, 2019
Package.swift Fix Package.swift Nov 29, 2019
Podfile Add TextField Nov 27, 2019
Podfile.lock Add TextField Nov 27, 2019
README.md Add .introspectViewController() Dec 10, 2019

README.md

Introspect for SwiftUI

CircleCI

Introspect allows you to get the underlying UIKit element of a SwiftUI view.

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

How it works

Introspect works by adding a custom IntrospectionView to the view hierarchy, then looking into the UIKit hierarchy to find the relevant view.

For instance, when introspecting a TextField, it will:

  • Add IntrospectionView as an overlay of TextField
  • Get the view host of the introspection view (which is alongside the view host of the UITextField)
  • Get the previous sibling containing UITextField

Please note that this introspection method might break in future SwiftUI releases. Future implementations might not use the same hierarchy, or might not use UIKit elements that are being looked for. Though the library is unlikely to crash, the .introspect() method will not be called in those cases.

Usage in production

Introspect 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 classes, and the introspect() methods are simply ignored if UIKit views cannot be found.

Install

SwiftPM

https://github.com/timbersoftware/SwiftUI-Introspect.git

Cocoapods

pod "Introspect"

Introspection

Implemented

SwiftUI UIKit Introspect Target
List UITableView .introspectTableView() List, or List child
ScrollView UIScrollView .introspectScrollView() ScrollView, or ScrollView child
NavigationView UINavigationController .introspectNavigationController() NavigationView, or NavigationView child
Any embedded view UIViewController .introspectViewController() View embedded in a view controller
TabView UITabBarController .introspectTabBarController() TabView, or TabView child
TextField UITextField .introspectTextField() TextField
Toggle UISwitch .introspectSwitch() Toggle
Slider UISlider .introspectSlider() Slider
Stepper UIStepper .introspectStepper() Stepper
DatePicker UIDatePicker .introspectDatePicker() DatePicker
Picker (SegmentedPickerStyle) UISegmentedControl .introspectSegmentedControl() Picker

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

Cannot implement

SwiftUI Why
Text Not a UILabel
Image Not a UIImageView
Button Not a UIButton

Examples

List

List {
    Text("Item 1")
    Text("Item 2")
}
.introspectTableView { tableView in
    tableView.separatorStyle = .none
}

ScrollView

ScrollView {
    Text("Item 2")
}
.introspectScrollView { scrollView in
    scrollView.refreshControl = UIRefreshControl()
}

NavigationView

NavigationView {
    Text("Item 2")
    .introspectNavigationController { navigationController in
        navigationController.navigationBar.backgroundColor = .red
    }
}

TextField

TextField("Text Field", text: $textFieldValue)
.introspectTextField { textField in
    textField.layer.backgroundColor = UIColor.red.cgColor
}

Implement your own selector

Missing an element? Please create an issue.

In case Introspect doesn't support the SwiftUI element that you're looking for, you can implement your own selector. For example, to look for a UITextField:

extension View {
    public func introspectTextField(customize: @escaping (UITextField) -> ()) -> some View {
        return inject(IntrospectionView(
            selector: { introspectionView in
                guard let viewHost = Introspect.findViewHost(from: introspectionView) else {
                    return nil
                }
                return Introspect.previousSibling(containing: UITextField.self, from: viewHost)
            },
            customize: customize
        ))
    }
}

You can use any of the following methods to inspect the hierarchy:

  • Introspect.findChild(ofType:in:)
  • Introspect.previousSibling(containing:from:)
  • Introspect.nextSibling(containing:from:)
  • Introspect.findAncestor(ofType:from:)
  • Introspect.findHostingView(from:)
  • Introspect.findViewHost(from:)
You can’t perform that action at this time.