Add TextField

This commit is contained in:
Lois Di Qual 2019-11-27 09:10:10 -08:00
parent 1b5e49486e
commit 7dd0c8aae0
13 changed files with 277 additions and 23 deletions

7
.gitignore vendored
View File

@ -49,12 +49,7 @@ playground.xcworkspace
.build/
# CocoaPods
#
# We recommend against adding the Pods directory to your .gitignore. However
# you should judge for yourself, the pros and cons are mentioned at:
# https://guides.cocoapods.org/using/using-cocoapods.html#should-i-check-the-pods-directory-into-source-control
#
# Pods/
Pods/
#
# Add this line if you want to avoid checking in source code from the Xcode workspace
# *.xcworkspace

1
.ruby-version Normal file
View File

@ -0,0 +1 @@
2.6.4

3
Gemfile Normal file
View File

@ -0,0 +1,3 @@
source "https://rubygems.org"
gem "cocoapods", "1.8.4"

83
Gemfile.lock Normal file
View File

@ -0,0 +1,83 @@
GEM
remote: https://rubygems.org/
specs:
CFPropertyList (3.0.1)
activesupport (4.2.11.1)
i18n (~> 0.7)
minitest (~> 5.1)
thread_safe (~> 0.3, >= 0.3.4)
tzinfo (~> 1.1)
algoliasearch (1.27.1)
httpclient (~> 2.8, >= 2.8.3)
json (>= 1.5.1)
atomos (0.1.3)
claide (1.0.3)
cocoapods (1.8.4)
activesupport (>= 4.0.2, < 5)
claide (>= 1.0.2, < 2.0)
cocoapods-core (= 1.8.4)
cocoapods-deintegrate (>= 1.0.3, < 2.0)
cocoapods-downloader (>= 1.2.2, < 2.0)
cocoapods-plugins (>= 1.0.0, < 2.0)
cocoapods-search (>= 1.0.0, < 2.0)
cocoapods-stats (>= 1.0.0, < 2.0)
cocoapods-trunk (>= 1.4.0, < 2.0)
cocoapods-try (>= 1.1.0, < 2.0)
colored2 (~> 3.1)
escape (~> 0.0.4)
fourflusher (>= 2.3.0, < 3.0)
gh_inspector (~> 1.0)
molinillo (~> 0.6.6)
nap (~> 1.0)
ruby-macho (~> 1.4)
xcodeproj (>= 1.11.1, < 2.0)
cocoapods-core (1.8.4)
activesupport (>= 4.0.2, < 6)
algoliasearch (~> 1.0)
concurrent-ruby (~> 1.1)
fuzzy_match (~> 2.0.4)
nap (~> 1.0)
cocoapods-deintegrate (1.0.4)
cocoapods-downloader (1.3.0)
cocoapods-plugins (1.0.0)
nap
cocoapods-search (1.0.0)
cocoapods-stats (1.1.0)
cocoapods-trunk (1.4.1)
nap (>= 0.8, < 2.0)
netrc (~> 0.11)
cocoapods-try (1.1.0)
colored2 (3.1.2)
concurrent-ruby (1.1.5)
escape (0.0.4)
fourflusher (2.3.1)
fuzzy_match (2.0.4)
gh_inspector (1.1.3)
httpclient (2.8.3)
i18n (0.9.5)
concurrent-ruby (~> 1.0)
json (2.2.0)
minitest (5.13.0)
molinillo (0.6.6)
nanaimo (0.2.6)
nap (1.1.0)
netrc (0.11.0)
ruby-macho (1.4.0)
thread_safe (0.3.6)
tzinfo (1.2.5)
thread_safe (~> 0.1)
xcodeproj (1.13.0)
CFPropertyList (>= 2.3.3, < 4.0)
atomos (~> 0.1.3)
claide (>= 1.0.2, < 2.0)
colored2 (~> 3.1)
nanaimo (~> 0.2.6)
PLATFORMS
ruby
DEPENDENCIES
cocoapods (= 1.8.4)
BUNDLED WITH
1.17.3

View File

@ -20,6 +20,7 @@
C0C6D697238E007100DA6285 /* Preview Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = C0C6D696238E007100DA6285 /* Preview Assets.xcassets */; };
C0C6D69A238E007100DA6285 /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = C0C6D698238E007100DA6285 /* LaunchScreen.storyboard */; };
C0C6D6A0238E00D300DA6285 /* Introspect.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = C0687012238DE85D00DAFD3D /* Introspect.framework */; };
E0B11E0609FFA04A7B6A1418 /* Pods_IntrospectExamples.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 5785749C354BCF848BC4EAD9 /* Pods_IntrospectExamples.framework */; };
/* End PBXBuildFile section */
/* Begin PBXContainerItemProxy section */
@ -33,6 +34,9 @@
/* End PBXContainerItemProxy section */
/* Begin PBXFileReference section */
5785749C354BCF848BC4EAD9 /* Pods_IntrospectExamples.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_IntrospectExamples.framework; sourceTree = BUILT_PRODUCTS_DIR; };
9BBE78DB32CCDC560004DB54 /* Pods-IntrospectExamples.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-IntrospectExamples.debug.xcconfig"; path = "Target Support Files/Pods-IntrospectExamples/Pods-IntrospectExamples.debug.xcconfig"; sourceTree = "<group>"; };
B826284199E111BBEA21E76B /* Pods-IntrospectExamples.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-IntrospectExamples.release.xcconfig"; path = "Target Support Files/Pods-IntrospectExamples/Pods-IntrospectExamples.release.xcconfig"; sourceTree = "<group>"; };
C0687012238DE85D00DAFD3D /* Introspect.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Introspect.framework; sourceTree = BUILT_PRODUCTS_DIR; };
C0687015238DE85D00DAFD3D /* Introspect.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = Introspect.h; sourceTree = "<group>"; };
C0687016238DE85D00DAFD3D /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
@ -73,12 +77,23 @@
buildActionMask = 2147483647;
files = (
C0C6D6A0238E00D300DA6285 /* Introspect.framework in Frameworks */,
E0B11E0609FFA04A7B6A1418 /* Pods_IntrospectExamples.framework in Frameworks */,
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXFrameworksBuildPhase section */
/* Begin PBXGroup section */
0534532308DF3E515053BF9F /* Pods */ = {
isa = PBXGroup;
children = (
9BBE78DB32CCDC560004DB54 /* Pods-IntrospectExamples.debug.xcconfig */,
B826284199E111BBEA21E76B /* Pods-IntrospectExamples.release.xcconfig */,
);
name = Pods;
path = Pods;
sourceTree = "<group>";
};
C0687008238DE85D00DAFD3D = {
isa = PBXGroup;
children = (
@ -87,6 +102,7 @@
C0C6D68C238E006B00DA6285 /* IntrospectExamples */,
C0687013238DE85D00DAFD3D /* Products */,
C0C6D69F238E00D300DA6285 /* Frameworks */,
0534532308DF3E515053BF9F /* Pods */,
);
sourceTree = "<group>";
};
@ -146,6 +162,7 @@
C0C6D69F238E00D300DA6285 /* Frameworks */ = {
isa = PBXGroup;
children = (
5785749C354BCF848BC4EAD9 /* Pods_IntrospectExamples.framework */,
);
name = Frameworks;
sourceTree = "<group>";
@ -204,9 +221,11 @@
isa = PBXNativeTarget;
buildConfigurationList = C0C6D69E238E007100DA6285 /* Build configuration list for PBXNativeTarget "IntrospectExamples" */;
buildPhases = (
9C6427CDD5EF4F1EAC75C7F9 /* [CP] Check Pods Manifest.lock */,
C0C6D687238E006B00DA6285 /* Sources */,
C0C6D688238E006B00DA6285 /* Frameworks */,
C0C6D689238E006B00DA6285 /* Resources */,
EC4E9FC6E0E62CFD8A53623A /* [CP] Embed Pods Frameworks */,
);
buildRules = (
);
@ -286,6 +305,48 @@
};
/* End PBXResourcesBuildPhase section */
/* Begin PBXShellScriptBuildPhase section */
9C6427CDD5EF4F1EAC75C7F9 /* [CP] Check Pods Manifest.lock */ = {
isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647;
files = (
);
inputFileListPaths = (
);
inputPaths = (
"${PODS_PODFILE_DIR_PATH}/Podfile.lock",
"${PODS_ROOT}/Manifest.lock",
);
name = "[CP] Check Pods Manifest.lock";
outputFileListPaths = (
);
outputPaths = (
"$(DERIVED_FILE_DIR)/Pods-IntrospectExamples-checkManifestLockResult.txt",
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n";
showEnvVarsInLog = 0;
};
EC4E9FC6E0E62CFD8A53623A /* [CP] Embed Pods Frameworks */ = {
isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647;
files = (
);
inputFileListPaths = (
"${PODS_ROOT}/Target Support Files/Pods-IntrospectExamples/Pods-IntrospectExamples-frameworks-${CONFIGURATION}-input-files.xcfilelist",
);
name = "[CP] Embed Pods Frameworks";
outputFileListPaths = (
"${PODS_ROOT}/Target Support Files/Pods-IntrospectExamples/Pods-IntrospectExamples-frameworks-${CONFIGURATION}-output-files.xcfilelist",
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-IntrospectExamples/Pods-IntrospectExamples-frameworks.sh\"\n";
showEnvVarsInLog = 0;
};
/* End PBXShellScriptBuildPhase section */
/* Begin PBXSourcesBuildPhase section */
C068700E238DE85D00DAFD3D /* Sources */ = {
isa = PBXSourcesBuildPhase;
@ -548,6 +609,7 @@
};
C0C6D69C238E007100DA6285 /* Debug */ = {
isa = XCBuildConfiguration;
baseConfigurationReference = 9BBE78DB32CCDC560004DB54 /* Pods-IntrospectExamples.debug.xcconfig */;
buildSettings = {
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
CODE_SIGN_STYLE = Automatic;
@ -567,6 +629,7 @@
};
C0C6D69D238E007100DA6285 /* Release */ = {
isa = XCBuildConfiguration;
baseConfigurationReference = B826284199E111BBEA21E76B /* Pods-IntrospectExamples.release.xcconfig */;
buildSettings = {
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
CODE_SIGN_STYLE = Automatic;

View File

@ -7,12 +7,12 @@
<key>Introspect.xcscheme_^#shared#^_</key>
<dict>
<key>orderHint</key>
<integer>0</integer>
<integer>2</integer>
</dict>
<key>IntrospectExamples.xcscheme_^#shared#^_</key>
<dict>
<key>orderHint</key>
<integer>1</integer>
<integer>3</integer>
</dict>
</dict>
</dict>

View File

@ -0,0 +1,10 @@
<?xml version="1.0" encoding="UTF-8"?>
<Workspace
version = "1.0">
<FileRef
location = "group:Introspect.xcodeproj">
</FileRef>
<FileRef
location = "group:Pods/Pods.xcodeproj">
</FileRef>
</Workspace>

View File

@ -0,0 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>IDEDidComputeMac32BitWarning</key>
<true/>
</dict>
</plist>

View File

@ -1,12 +1,16 @@
import SwiftUI
public enum Introspect {
public static func findChild<AnyViewType: UIView>(ofType type: AnyViewType.Type, in root: UIView) -> AnyViewType? {
public static func findChild<AnyViewType: UIView>(
ofType type: AnyViewType.Type,
in root: UIView
) -> AnyViewType? {
for subview in root.subviews {
if let tableView = subview as? AnyViewType {
return tableView
} else if let tableView = findChild(ofType: type, in: subview) {
return tableView
if let typed = subview as? AnyViewType {
return typed
} else if let typed = findChild(ofType: type, in: subview) {
return typed
}
}
return nil
@ -22,11 +26,44 @@ public enum Introspect {
}
return nil
}
public static func findHostingView(from entry: UIView) -> UIView? {
var superview = entry.superview
while let s = superview {
if NSStringFromClass(type(of: s)).contains("UIHostingView") {
return s
}
superview = s.superview
}
return nil
}
public static func findViewHost(from entry: UIView) -> UIView? {
var superview = entry.superview
while let s = superview {
if NSStringFromClass(type(of: s)).contains("ViewHost") {
return s
}
superview = s.superview
}
return nil
}
}
// Allows to safely access an array element by index
// Usage: array[safe: 2]
private extension Array {
public subscript(safe index: Int) -> Element? {
guard index >= 0, index < endIndex else {
return nil
}
return self[index]
}
}
public struct IntrospectionView<ViewType: UIView>: UIViewRepresentable {
let selector: (UIView) -> ViewType?
let customize: (ViewType) -> Void
@ -39,7 +76,9 @@ public struct IntrospectionView<ViewType: UIView>: UIViewRepresentable {
}
public func makeUIView(context: UIViewRepresentableContext<IntrospectionView>) -> UIView {
return UIView(frame: .zero)
let view = UIView(frame: .zero)
view.accessibilityLabel = "IntrospectionUIView<\(ViewType.self)>"
return view
}
public func updateUIView(_ uiView: UIView, context: UIViewRepresentableContext<IntrospectionView>) {
@ -93,8 +132,8 @@ public struct IntrospectionViewController<ViewControllerType: UIViewController>:
extension View {
public func introspectTableView(customize: @escaping (UITableView) -> ()) -> some View {
return background(IntrospectionView(
selector: { viewHost in
Introspect.findAncestor(ofType: UITableView.self, from: viewHost)
selector: { introspectionView in
Introspect.findAncestor(ofType: UITableView.self, from: introspectionView)
},
customize: customize
))
@ -106,5 +145,27 @@ extension View {
customize: customize
))
}
public func introspectTextField(customize: @escaping (UITextField) -> ()) -> some View {
return self.background(IntrospectionView(
selector: { introspectionView in
guard let viewHost = Introspect.findViewHost(from: introspectionView) else {
return nil
}
guard let container = viewHost.superview,
let viewHostIndex = container.subviews.firstIndex(of: viewHost),
let textFieldContainer = container.subviews[safe: viewHostIndex + 1]
else {
return nil
}
return Introspect.findChild(
ofType: UITextField.self,
in: textFieldContainer
)
},
customize: customize
))
}
}

View File

@ -61,12 +61,17 @@ struct NavigationExample: View {
}
struct SimpleElementsExample: View {
@State private var selection = 0
@State private var test = ""
var body: some View {
HStack {
Image(systemName: "folder")
.introspectImageView { imageView in
TextField("Red", text: $test)
.introspectTextField { textField in
textField.layer.backgroundColor = UIColor.red.cgColor
}
TextField("Green", text: $test)
.introspectTextField { textField in
textField.layer.backgroundColor = UIColor.green.cgColor
}
}
}

9
Podfile Normal file
View File

@ -0,0 +1,9 @@
platform :ios, "13.0"
inhibit_all_warnings!
use_frameworks!
# Disable sending stats (takes too much time)
ENV["COCOAPODS_DISABLE_STATS"] = "true"
target "IntrospectExamples"
pod "Reveal-SDK", "24", :configurations => ['Debug']

16
Podfile.lock Normal file
View File

@ -0,0 +1,16 @@
PODS:
- Reveal-SDK (24)
DEPENDENCIES:
- Reveal-SDK (= 24)
SPEC REPOS:
trunk:
- Reveal-SDK
SPEC CHECKSUMS:
Reveal-SDK: 5d7e56b8f018c0a88b3a2c10bf68d598bbd3b071
PODFILE CHECKSUM: 3558c3b60c01e8cff4f7b0ac1bd6ef19441afc81
COCOAPODS: 1.8.4

View File

@ -9,13 +9,13 @@ SwiftUI | UIKit | Introspect
--- | --- | ---
List | UITableView | `.introspectTableView()` on a list child
NavigationView | UINavigationController | `.introspectNavigationController()` on a navigation child
TextField | UITextField | `.introspectTextField()`
### Not implemented
SwiftUI | UIKit
--- | ---
TextField | UITextField
Toggle | UISwitch
Slider | UISlider
Button | UIButton