diff --git a/MagazineLayout/LayoutCore/Types/TargetContentOffsetAnchor.swift b/MagazineLayout/LayoutCore/Types/TargetContentOffsetAnchor.swift index a594285..0f1bff5 100644 --- a/MagazineLayout/LayoutCore/Types/TargetContentOffsetAnchor.swift +++ b/MagazineLayout/LayoutCore/Types/TargetContentOffsetAnchor.swift @@ -40,10 +40,19 @@ enum TargetContentOffsetAnchor: Equatable { { let top = (-topInset).alignedToPixel(forScreenWithScale: scale) let bottom = (contentHeight + bottomInset - bounds.height).alignedToPixel(forScreenWithScale: scale) + let isAtTop = bounds.minY <= top + let isAtBottom = bounds.minY >= bottom let position: Position - if bounds.minY <= top { + if isAtTop, isAtBottom { + switch verticalLayoutDirection { + case .topToBottom: + position = .atTop + case .bottomToTop: + position = .atBottom + } + } else if isAtTop { position = .atTop - } else if bounds.minY >= bottom { + } else if isAtBottom { position = .atBottom } else { position = .inMiddle diff --git a/Tests/TargetContentOffsetAnchorTests.swift b/Tests/TargetContentOffsetAnchorTests.swift index 3db614c..92bc1d3 100644 --- a/Tests/TargetContentOffsetAnchorTests.swift +++ b/Tests/TargetContentOffsetAnchorTests.swift @@ -66,6 +66,21 @@ final class TargetContentOffsetAnchorTests: XCTestCase { XCTAssert(anchor == .topItem(id: "6", itemEdge: .top, distanceFromTop: 20)) } + func testAnchor_TopToBottom_SmallContentHeight() throws { + let anchor = TargetContentOffsetAnchor.targetContentOffsetAnchor( + verticalLayoutDirection: .topToBottom, + topInset: 50, + bottomInset: 30, + bounds: CGRect(x: 0, y: -50, width: 300, height: 400), + contentHeight: 50, + scale: 1, + firstVisibleItemID: "0", + lastVisibleItemID: "1", + firstVisibleItemFrame: CGRect(x: 0, y: 0, width: 300, height: 20), + lastVisibleItemFrame: CGRect(x: 0, y: 30, width: 300, height: 20)) + XCTAssert(anchor == .top) + } + // MARK: Bottom-to-Top Anchor Tests func testAnchor_BottomToTop_ScrolledToTop() throws { @@ -113,7 +128,22 @@ final class TargetContentOffsetAnchorTests: XCTestCase { XCTAssert(anchor == .bottom) } - // MARK: To-to-Bottom Target Content Offset Tests + func testAnchor_BottomToTop_SmallContentHeight() throws { + let anchor = TargetContentOffsetAnchor.targetContentOffsetAnchor( + verticalLayoutDirection: .bottomToTop, + topInset: 50, + bottomInset: 30, + bounds: CGRect(x: 0, y: -50, width: 300, height: 400), + contentHeight: 50, + scale: 1, + firstVisibleItemID: "0", + lastVisibleItemID: "1", + firstVisibleItemFrame: CGRect(x: 0, y: 0, width: 300, height: 20), + lastVisibleItemFrame: CGRect(x: 0, y: 30, width: 300, height: 20)) + XCTAssert(anchor == .bottom) + } + + // MARK: Top-to-Bottom Target Content Offset Tests func testOffset_TopToBottom_ScrolledToTop() { let anchor = TargetContentOffsetAnchor.top