Skip to content

Commit bad095e

Browse files
paescebuPascal Burletdavdroman
authored
Fix finding UIScrollViews that are clipped(), masked or combined with clipShape() or cornerRadius() (#213)
Co-authored-by: Pascal Burlet <pascal.burlet@lhsystems.com> Co-authored-by: David Roman <2538074+davdroman@users.noreply.github.com>
1 parent a2b9069 commit bad095e

File tree

4 files changed

+120
-3
lines changed

4 files changed

+120
-3
lines changed

Introspect/Introspect.swift

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -318,6 +318,16 @@ public enum TargetViewSelector {
318318
}
319319
return Introspect.findAncestor(ofType: TargetView.self, from: entry)
320320
}
321+
322+
public static func siblingOrAncestorOrSiblingContainingOrAncestorChild<TargetView: PlatformView>(from entry: PlatformView) -> TargetView? {
323+
if let sibling: TargetView = siblingOfType(from: entry) {
324+
return sibling
325+
}
326+
if let ancestor: TargetView = Introspect.findAncestor(ofType: TargetView.self, from: entry) {
327+
return ancestor
328+
}
329+
return siblingContainingOrAncestorOrAncestorChild(from: entry)
330+
}
321331

322332
public static func ancestorOrSiblingContaining<TargetView: PlatformView>(from entry: PlatformView) -> TargetView? {
323333
if let tableView = Introspect.findAncestor(ofType: TargetView.self, from: entry) {

Introspect/ViewExtensions.swift

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -120,7 +120,7 @@ extension View {
120120
/// Finds a `UIScrollView` from a `SwiftUI.ScrollView`, or `SwiftUI.ScrollView` child.
121121
public func introspectScrollView(customize: @escaping (UIScrollView) -> ()) -> some View {
122122
if #available(iOS 14, tvOS 14, *) {
123-
return introspect(selector: TargetViewSelector.siblingOfTypeOrAncestor, customize: customize)
123+
return introspect(selector: TargetViewSelector.siblingOrAncestorOrSiblingContainingOrAncestorChild, customize: customize)
124124
} else {
125125
return introspect(selector: TargetViewSelector.siblingContainingOrAncestor, customize: customize)
126126
}
@@ -227,7 +227,7 @@ extension View {
227227
/// Finds a `NSScrollView` from a `SwiftUI.ScrollView`, or `SwiftUI.ScrollView` child.
228228
public func introspectScrollView(customize: @escaping (NSScrollView) -> ()) -> some View {
229229
if #available(macOS 11, *) {
230-
return introspect(selector: TargetViewSelector.siblingOfTypeOrAncestor, customize: customize)
230+
return introspect(selector: TargetViewSelector.siblingOrAncestorOrSiblingContainingOrAncestorChild, customize: customize)
231231
} else {
232232
return introspect(selector: TargetViewSelector.siblingContainingOrAncestor, customize: customize)
233233
}

IntrospectTests/AppKitTests.swift

Lines changed: 53 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -113,6 +113,32 @@ private struct NestedScrollTestView: View {
113113
}
114114
}
115115

116+
private struct MaskedScrollTestView: View {
117+
118+
let spy1: (NSScrollView) -> Void
119+
let spy2: (NSScrollView) -> Void
120+
121+
var body: some View {
122+
HStack {
123+
ScrollView {
124+
Text("Item 1")
125+
}
126+
.introspectScrollView { scrollView in
127+
self.spy1(scrollView)
128+
}
129+
.clipped()
130+
.clipShape(RoundedRectangle(cornerRadius: 20.0))
131+
.cornerRadius(2.0)
132+
ScrollView {
133+
Text("Item 1")
134+
.introspectScrollView { scrollView in
135+
self.spy2(scrollView)
136+
}
137+
}
138+
}
139+
}
140+
}
141+
116142
private struct TextFieldTestView: View {
117143
let spy: () -> Void
118144
@State private var textFieldValue = ""
@@ -314,7 +340,6 @@ class AppKitTests: XCTestCase {
314340
}
315341

316342
func testNestedScrollView() throws {
317-
318343
let expectation1 = XCTestExpectation()
319344
let expectation2 = XCTestExpectation()
320345

@@ -339,6 +364,33 @@ class AppKitTests: XCTestCase {
339364

340365
XCTAssertNotEqual(unwrappedScrollView1, unwrappedScrollView2)
341366
}
367+
368+
func testMaskedScrollView() throws {
369+
let expectation1 = XCTestExpectation()
370+
let expectation2 = XCTestExpectation()
371+
372+
var scrollView1: NSScrollView?
373+
var scrollView2: NSScrollView?
374+
375+
let view = MaskedScrollTestView(
376+
spy1: { scrollView in
377+
scrollView1 = scrollView
378+
expectation1.fulfill()
379+
},
380+
spy2: { scrollView in
381+
scrollView2 = scrollView
382+
expectation2.fulfill()
383+
}
384+
)
385+
386+
TestUtils.present(view: view)
387+
wait(for: [expectation1, expectation2], timeout: TestUtils.Constants.timeout)
388+
389+
let unwrappedScrollView1 = try XCTUnwrap(scrollView1)
390+
let unwrappedScrollView2 = try XCTUnwrap(scrollView2)
391+
392+
XCTAssertNotEqual(unwrappedScrollView1, unwrappedScrollView2)
393+
}
342394

343395
func testTextField() {
344396

IntrospectTests/UIKitTests.swift

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -183,6 +183,7 @@ private struct ListTestView: View {
183183
}
184184
}
185185

186+
186187
private struct ScrollTestView: View {
187188

188189
let spy1: (UIScrollView) -> Void
@@ -230,6 +231,32 @@ private struct NestedScrollTestView: View {
230231
}
231232
}
232233

234+
private struct MaskedScrollTestView: View {
235+
236+
let spy1: (UIScrollView) -> Void
237+
let spy2: (UIScrollView) -> Void
238+
239+
var body: some View {
240+
HStack {
241+
ScrollView {
242+
Text("Item 1")
243+
}
244+
.introspectScrollView { scrollView in
245+
self.spy1(scrollView)
246+
}
247+
.clipped()
248+
.clipShape(RoundedRectangle(cornerRadius: 20.0))
249+
.cornerRadius(2.0)
250+
ScrollView {
251+
Text("Item 1")
252+
.introspectScrollView { scrollView in
253+
self.spy2(scrollView)
254+
}
255+
}
256+
}
257+
}
258+
}
259+
233260
private struct TextFieldTestView: View {
234261
let spy1: (UITextField) -> Void
235262
let spy2: (UITextField) -> Void
@@ -482,6 +509,34 @@ class UIKitTests: XCTestCase {
482509

483510
XCTAssertNotEqual(unwrappedScrollView1, unwrappedScrollView2)
484511
}
512+
513+
func testMaskedScrollView() throws {
514+
515+
let expectation1 = XCTestExpectation()
516+
let expectation2 = XCTestExpectation()
517+
518+
var scrollView1: UIScrollView?
519+
var scrollView2: UIScrollView?
520+
521+
let view = MaskedScrollTestView(
522+
spy1: { scrollView in
523+
scrollView1 = scrollView
524+
expectation1.fulfill()
525+
},
526+
spy2: { scrollView in
527+
scrollView2 = scrollView
528+
expectation2.fulfill()
529+
}
530+
)
531+
532+
TestUtils.present(view: view)
533+
wait(for: [expectation1, expectation2], timeout: TestUtils.Constants.timeout)
534+
535+
let unwrappedScrollView1 = try XCTUnwrap(scrollView1)
536+
let unwrappedScrollView2 = try XCTUnwrap(scrollView2)
537+
538+
XCTAssertNotEqual(unwrappedScrollView1, unwrappedScrollView2)
539+
}
485540

486541
func testTextField() throws {
487542

0 commit comments

Comments
 (0)