Fix UITextField with cornerRadius (#83)
This commit is contained in:
parent
fab6cddbaf
commit
07a80dd280
|
@ -3,6 +3,7 @@ Changelog
|
|||
|
||||
## master
|
||||
|
||||
- Fix UITextField with cornerRadius
|
||||
- Added `.introspectTabView()` on macOS
|
||||
|
||||
## [0.1.3]
|
||||
|
|
|
@ -51,6 +51,39 @@ public enum Introspect {
|
|||
return nil
|
||||
}
|
||||
|
||||
/// Finds a subview of the specified type.
|
||||
/// This method will recursively look for this view.
|
||||
/// Returns nil if it can't find a view of the specified type.
|
||||
public static func findChildUsingFrame<AnyViewType: PlatformView>(
|
||||
ofType type: AnyViewType.Type,
|
||||
in root: PlatformView,
|
||||
from originalEntry: PlatformView
|
||||
) -> AnyViewType? {
|
||||
var children: [AnyViewType] = []
|
||||
for subview in root.subviews {
|
||||
if let typed = subview as? AnyViewType {
|
||||
children.append(typed)
|
||||
} else if let typed = findChild(ofType: type, in: subview) {
|
||||
children.append(typed)
|
||||
}
|
||||
}
|
||||
|
||||
if children.count > 1 {
|
||||
for child in children {
|
||||
let converted = child.convert(
|
||||
CGPoint(x: originalEntry.frame.size.width / 2, y: originalEntry.frame.size.height / 2),
|
||||
from: originalEntry
|
||||
)
|
||||
if CGRect(origin: .zero, size: child.frame.size).contains(converted) {
|
||||
return child
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
return children.first
|
||||
}
|
||||
|
||||
/// Finds a previous sibling that contains a view of the specified type.
|
||||
/// This method inspects siblings recursively.
|
||||
/// Returns nil if no sibling contains the specified type.
|
||||
|
@ -207,6 +240,19 @@ public enum Introspect {
|
|||
return nil
|
||||
}
|
||||
|
||||
/// Finds an ancestor of the specified type.
|
||||
/// If it reaches the top of the view without finding the specified view type, it returns nil.
|
||||
public static func findAncestorOrAncestorChild<AnyViewType: PlatformView>(ofType type: AnyViewType.Type, from entry: PlatformView) -> AnyViewType? {
|
||||
var superview = entry.superview
|
||||
while let s = superview {
|
||||
if let typed = s as? AnyViewType ?? findChildUsingFrame(ofType: type, in: s, from: entry) {
|
||||
return typed
|
||||
}
|
||||
superview = s.superview
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
/// Finds the hosting view of a specific subview.
|
||||
/// Hosting views generally contain subviews for one specific SwiftUI element.
|
||||
/// For instance, if there are multiple text fields in a VStack, the hosting view will contain those text fields (and their host views, see below).
|
||||
|
@ -252,6 +298,13 @@ public enum TargetViewSelector {
|
|||
return Introspect.findAncestor(ofType: TargetView.self, from: entry)
|
||||
}
|
||||
|
||||
public static func siblingContainingOrAncestorOrAncestorChild<TargetView: PlatformView>(from entry: PlatformView) -> TargetView? {
|
||||
if let sibling: TargetView = siblingContaining(from: entry) {
|
||||
return sibling
|
||||
}
|
||||
return Introspect.findAncestorOrAncestorChild(ofType: TargetView.self, from: entry)
|
||||
}
|
||||
|
||||
public static func siblingOfType<TargetView: PlatformView>(from entry: PlatformView) -> TargetView? {
|
||||
guard let viewHost = Introspect.findViewHost(from: entry) else {
|
||||
return nil
|
||||
|
|
|
@ -91,7 +91,7 @@ extension View {
|
|||
|
||||
/// Finds a `UITextField` from a `SwiftUI.TextField`
|
||||
public func introspectTextField(customize: @escaping (UITextField) -> ()) -> some View {
|
||||
return introspect(selector: TargetViewSelector.siblingContaining, customize: customize)
|
||||
return introspect(selector: TargetViewSelector.siblingContainingOrAncestorOrAncestorChild, customize: customize)
|
||||
}
|
||||
|
||||
/// Finds a `UITextView` from a `SwiftUI.TextEditor`
|
||||
|
|
|
@ -188,12 +188,31 @@ private struct NestedScrollTestView: View {
|
|||
|
||||
@available(iOS 13.0, tvOS 13.0, macOS 10.15.0, *)
|
||||
private struct TextFieldTestView: View {
|
||||
let spy: () -> Void
|
||||
let spy1: (UITextField) -> Void
|
||||
let spy2: (UITextField) -> Void
|
||||
let spy3: (UITextField) -> Void
|
||||
@State private var textFieldValue = ""
|
||||
|
||||
let textField1Placeholder = "Text Field 1"
|
||||
let textField2Placeholder = "Text Field 2"
|
||||
let textField3Placeholder = "Text Field 3"
|
||||
|
||||
var body: some View {
|
||||
TextField("Text Field", text: $textFieldValue)
|
||||
.introspectTextField { textField in
|
||||
self.spy()
|
||||
VStack {
|
||||
TextField(textField1Placeholder, text: $textFieldValue)
|
||||
.introspectTextField { textField in
|
||||
self.spy1(textField)
|
||||
}
|
||||
.cornerRadius(8)
|
||||
TextField(textField2Placeholder, text: $textFieldValue)
|
||||
.introspectTextField { textField in
|
||||
self.spy2(textField)
|
||||
}
|
||||
.cornerRadius(8)
|
||||
TextField(textField3Placeholder, text: $textFieldValue)
|
||||
.introspectTextField { textField in
|
||||
self.spy3(textField)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -396,14 +415,40 @@ class UIKitTests: XCTestCase {
|
|||
XCTAssertNotEqual(unwrappedScrollView1, unwrappedScrollView2)
|
||||
}
|
||||
|
||||
func testTextField() {
|
||||
func testTextField() throws {
|
||||
|
||||
let expectation = XCTestExpectation()
|
||||
let view = TextFieldTestView(spy: {
|
||||
expectation.fulfill()
|
||||
})
|
||||
let expectation1 = XCTestExpectation()
|
||||
let expectation2 = XCTestExpectation()
|
||||
let expectation3 = XCTestExpectation()
|
||||
|
||||
var textField1: UITextField?
|
||||
var textField2: UITextField?
|
||||
var textField3: UITextField?
|
||||
|
||||
let view = TextFieldTestView(
|
||||
spy1: {
|
||||
textField1 = $0
|
||||
expectation1.fulfill()
|
||||
},
|
||||
spy2: {
|
||||
textField2 = $0
|
||||
expectation2.fulfill()
|
||||
},
|
||||
spy3: {
|
||||
textField3 = $0
|
||||
expectation3.fulfill()
|
||||
}
|
||||
)
|
||||
TestUtils.present(view: view)
|
||||
wait(for: [expectation], timeout: TestUtils.Constants.timeout)
|
||||
wait(for: [expectation1, expectation2, expectation3], timeout: TestUtils.Constants.timeout)
|
||||
|
||||
let unwrappedTextField1 = try XCTUnwrap(textField1)
|
||||
let unwrappedTextField2 = try XCTUnwrap(textField2)
|
||||
let unwrappedTextField3 = try XCTUnwrap(textField3)
|
||||
|
||||
XCTAssertEqual(unwrappedTextField1.placeholder, view.textField1Placeholder)
|
||||
XCTAssertEqual(unwrappedTextField2.placeholder, view.textField2Placeholder)
|
||||
XCTAssertEqual(unwrappedTextField3.placeholder, view.textField3Placeholder)
|
||||
}
|
||||
|
||||
func testSegmentedControl() {
|
||||
|
|
Loading…
Reference in New Issue