Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,9 @@

### Added

- Added `targetIndexPath(forInteractivelyMovingItem:withPosition:)` protocol method to `ListLayout`, allowing custom layouts to override drop target determination during interactive reordering.
- Added `isReorderable` property on `ListLayoutContent.ItemInfo` to check if an item has reordering enabled.

### Removed

### Changed
Expand Down
12 changes: 9 additions & 3 deletions ListableUI/Sources/Layout/CollectionViewLayout.swift
Original file line number Diff line number Diff line change
Expand Up @@ -623,9 +623,15 @@ final class CollectionViewLayout : UICollectionViewLayout
withPosition position: CGPoint
) -> IndexPath {

/// TODO: The default implementation provided by `UICollectionView` does not work correctly
/// when trying to move an item to the end of a section, or when trying to move an item into an
/// empty section. We should add casing that allows moving into the section in these cases.
Comment on lines -626 to -628
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

do we need to keep this TODO?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think it's still true, it doesn't hurt to keep it, IMO (but then also, the TODO has been here forever, so I don't care either way)

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm okay either way. I lean towards removing since we don't have a good repro on file. I did some local testing and haven't run across these reordering issues on iOS 16 or iOS 26, so the issue may be fixed!

// Allow custom layouts to provide layout-aware drop targeting.
// This fixes issues with UICollectionView's default implementation which doesn't
// work correctly for some layout types.
if let customTarget = self.layout.targetIndexPath(
forInteractivelyMovingItem: previousIndexPath,
withPosition: position
) {
return customTarget
}

return super.targetIndexPath(forInteractivelyMovingItem: previousIndexPath, withPosition: position)
}
Expand Down
24 changes: 24 additions & 0 deletions ListableUI/Sources/Layout/ListLayout/ListLayout.swift
Original file line number Diff line number Diff line change
Expand Up @@ -168,6 +168,21 @@ public protocol AnyListLayout : AnyObject
at indexPath: IndexPath,
withTargetPosition position: CGPoint
)

/// Returns the target index path for an item being interactively moved.
///
/// Custom layouts can override this to provide layout-aware drop target
/// determination. The default implementation returns `nil`, which causes
/// `CollectionViewLayout` to fall back to UICollectionView's default behavior.
///
/// - Parameters:
/// - previousIndexPath: The current index path of the item being moved.
/// - position: The current position of the item in the collection view's coordinate space.
/// - Returns: The target index path if the layout can determine it, or `nil` to use default behavior.
func targetIndexPath(
forInteractivelyMovingItem previousIndexPath: IndexPath,
withPosition position: CGPoint
) -> IndexPath?
}


Expand Down Expand Up @@ -338,6 +353,15 @@ extension ListLayout
) {
// Nothing. Just a default implementation.
}

public func targetIndexPath(
forInteractivelyMovingItem previousIndexPath: IndexPath,
withPosition position: CGPoint
) -> IndexPath? {
// Default: return nil to use UICollectionView's default behavior.
// Custom layouts can override this for layout-aware drop targeting.
nil
}

private static func isHeaderSticky(
list: Bool,
Expand Down
5 changes: 5 additions & 0 deletions ListableUI/Sources/Layout/ListLayout/ListLayoutContent.swift
Original file line number Diff line number Diff line change
Expand Up @@ -510,6 +510,11 @@ extension ListLayoutContent
public var layouts : ItemLayouts {
self.state.anyModel.layouts
}

/// Whether this item can be reordered (has reordering configuration).
public var isReorderable: Bool {
self.state.anyModel.reordering != nil
}

public var frame : CGRect {
CGRect(
Expand Down
Loading