diff --git a/Example/MagazineLayoutExample/GridDemoViewController.swift b/Example/MagazineLayoutExample/GridDemoViewController.swift index ddf3454..51cbc37 100644 --- a/Example/MagazineLayoutExample/GridDemoViewController.swift +++ b/Example/MagazineLayoutExample/GridDemoViewController.swift @@ -291,23 +291,7 @@ extension GridDemoViewController: UICollectionViewDelegateMagazineLayout { private struct GridItem: Hashable { - // MARK: Lifecycle - - init( - id: UUID = UUID(), - text: String, - color: UIColor, - widthMode: MagazineLayoutItemWidthMode) - { - self.id = id - self.text = text - self.color = color - self.widthMode = widthMode - } - - // MARK: Internal - - let id: UUID + let id = UUID() let text: String let color: UIColor let widthMode: MagazineLayoutItemWidthMode diff --git a/Example/MagazineLayoutExample/ListDemoViewController.swift b/Example/MagazineLayoutExample/ListDemoViewController.swift index 2e33247..62c6552 100644 --- a/Example/MagazineLayoutExample/ListDemoViewController.swift +++ b/Example/MagazineLayoutExample/ListDemoViewController.swift @@ -383,23 +383,7 @@ private struct ListSection: Hashable { private struct ListItem: Hashable { - // MARK: Lifecycle - - init( - id: UUID = UUID(), - title: String, - subtitle: String, - color: UIColor) - { - self.id = id - self.title = title - self.subtitle = subtitle - self.color = color - } - - // MARK: Internal - - let id: UUID + let id = UUID() let title: String let subtitle: String let color: UIColor diff --git a/Example/MagazineLayoutExample/MessageThreadDemoViewController.swift b/Example/MagazineLayoutExample/MessageThreadDemoViewController.swift index bd0c8d2..d4bd105 100644 --- a/Example/MagazineLayoutExample/MessageThreadDemoViewController.swift +++ b/Example/MagazineLayoutExample/MessageThreadDemoViewController.swift @@ -302,12 +302,10 @@ private struct Message: Hashable { // MARK: Lifecycle init( - id: UUID = UUID(), text: String, isSent: Bool, timestamp: Date = Date()) { - self.id = id self.text = text self.isSent = isSent self.timestamp = timestamp @@ -315,7 +313,7 @@ private struct Message: Hashable { // MARK: Internal - let id: UUID + let id = UUID() let text: String let isSent: Bool let timestamp: Date diff --git a/MagazineLayout/LayoutCore/LayoutState.swift b/MagazineLayout/LayoutCore/LayoutState.swift index 69b88f5..58c9d6c 100644 --- a/MagazineLayout/LayoutCore/LayoutState.swift +++ b/MagazineLayout/LayoutCore/LayoutState.swift @@ -64,6 +64,8 @@ struct LayoutState { var targetContentOffsetAnchor: TargetContentOffsetAnchor { var visibleItemLocationFramePairs = [ElementLocationFramePair]() for itemLocationFramePair in modelState.itemLocationFramePairs(forItemsIn: bounds) { + // Only consider fully-visible items + guard bounds.contains(itemLocationFramePair.frame) else { continue } visibleItemLocationFramePairs.append(itemLocationFramePair) } visibleItemLocationFramePairs.sort { $0.elementLocation < $1.elementLocation } @@ -74,7 +76,7 @@ struct LayoutState { modelState.isItemHeightSettled(indexPath: $0.elementLocation.indexPath) } ?? visibleItemLocationFramePairs.first // fallback to the first item if we can't find one with a settled height - let lastVisibleItemLocationFramePair = visibleItemLocationFramePairs.reversed().first { + let lastVisibleItemLocationFramePair = visibleItemLocationFramePairs.last { // When scrolling down, only calculate a target content offset based on visible, already-sized // cells. Otherwise, scrolling will be jumpy. modelState.isItemHeightSettled(indexPath: $0.elementLocation.indexPath) diff --git a/Tests/LayoutStateTargetContentOffsetTests.swift b/Tests/LayoutStateTargetContentOffsetTests.swift index e2cc1bf..7367ce9 100644 --- a/Tests/LayoutStateTargetContentOffsetTests.swift +++ b/Tests/LayoutStateTargetContentOffsetTests.swift @@ -40,8 +40,8 @@ final class LayoutStateTargetContentOffsetTests: XCTestCase { contentInset: UIEdgeInsets(top: 50, left: 0, bottom: 30, right: 0), scale: 1, verticalLayoutDirection: .topToBottom) - let id = layoutState.modelState.idForItemModel(at: IndexPath(item: 5, section: 0))! - XCTAssert(layoutState.targetContentOffsetAnchor == .topItem(id: id, distanceFromTop: -160)) + let id = layoutState.modelState.idForItemModel(at: IndexPath(item: 6, section: 0))! + XCTAssert(layoutState.targetContentOffsetAnchor == .topItem(id: id, distanceFromTop: -25)) } func testAnchor_TopToBottom_ScrolledToBottom() throws { @@ -61,8 +61,8 @@ final class LayoutStateTargetContentOffsetTests: XCTestCase { contentInset: measurementLayoutState.contentInset, scale: measurementLayoutState.scale, verticalLayoutDirection: measurementLayoutState.verticalLayoutDirection) - let id = layoutState.modelState.idForItemModel(at: IndexPath(item: 7, section: 0))! - XCTAssert(layoutState.targetContentOffsetAnchor == .topItem(id: id, distanceFromTop: -80)) + let id = layoutState.modelState.idForItemModel(at: IndexPath(item: 9, section: 0))! + XCTAssert(layoutState.targetContentOffsetAnchor == .topItem(id: id, distanceFromTop: 25)) } // MARK: Bottom-to-Top Anchor Tests @@ -87,8 +87,8 @@ final class LayoutStateTargetContentOffsetTests: XCTestCase { contentInset: UIEdgeInsets(top: 50, left: 0, bottom: 30, right: 0), scale: 1, verticalLayoutDirection: .bottomToTop) - let id = layoutState.modelState.idForItemModel(at: IndexPath(item: 12, section: 0))! - XCTAssert(layoutState.targetContentOffsetAnchor == .bottomItem(id: id, distanceFromBottom: 190)) + let id = layoutState.modelState.idForItemModel(at: IndexPath(item: 10, section: 0))! + XCTAssert(layoutState.targetContentOffsetAnchor == .bottomItem(id: id, distanceFromBottom: -10)) } func testAnchor_BottomToTop_ScrolledToBottom() throws {