iOS UITableView limit reordering only in one section
Use the table view delegate method tableView:targetIndexPathForMoveFromRowAtIndexPath:toProposedIndexPath:
to check the proposed index path and return an index path in a different section if the user choice isn't acceptable.
Reordering sections in UITableView
There is no native functionality to achieve what you want. If I understand correctly you would want to collapse a whole section of rows and then start dragging the "header" around. If you want to do this on your own I would suggest starting with a pan gesture recognizer which triggers on the header button.
The gesture should be relatively obvious. After it starts on the header you need to track position using locationIn
in your table view.
To collapse rows all you need to do is modify your table view cells with appropriate animation like:
tableView.beginUpdates()
tableView.deleteSections([myIndexPath], with: .top) // Maybe experiment with animation type
// Modify whatever you need to correspond this change in the data source
tableView.endUpdates()
Since you will be removing the section you will also be removing the view (header) which has the gesture recognizer. That means it might be better adding the gesture to the table view directly or its superview even. You will need to force it to trigger only when one of those buttons on headers is pressed. You can get some idea here about it. The rest is unaffected by this change.
At this point you will probably need to create an extra view which represents your section stack and follows your finger. This should be pretty easy if you add it as a subview and manipulate it's center with pan gesture recognizer locationIn
in it's superview:
movableSectionView.center = panGestureRecognizer.location(in: movableSectionView.superview!)
So up to this point you should be able to grab a section which collapses all cells and be able to drag the "section stack" view around. Now you need to check where in table view your finger is to know where to drop the section. This is a bit painful but can be done with visibleCells
and tableView.indexPath(for: )
:
func indexPathForGestureRecognizer(_ recognizer: UIGestureRecognizer) -> IndexPath {
let coordinateView: UIView = tableView.superview! // This can actually be pretty much anything as long as it is in hierarchy
let y = recognizer.location(in: coordinateView).y
if let hitCell = tableView.visibleCells.first(where: { cell in
let frameInCoordinateView = cell.convert(cell.bounds, to: coordinateView)
return frameInCoordinateView.minY >= y && frameInCoordinateView.maxY <= y
}) {
// We have the cell at which the finger is. Retrieve the index path
return tableView.indexPath(for: hitCell) ?? IndexPath(row: 0, section: 0) // This should always succeed but just in case
} else {
// We may be out of bounds. That may be either too high which means above the table view otherwise too low
if recognizer.location(in: tableView).y < 0.0 {
return IndexPath(row: 0, section: 0)
} else {
guard tableView.numberOfSections > 0 else {
return IndexPath(row: 0, section: 0) // Nothing in the table view at all
}
let section = tableView.numberOfSections-1
return IndexPath(row: tableView.numberOfRows(inSection: section), section: section)
}
}
}
Once the gesture recognizer ends you can use this method to get the section you are dropping your items into. So just:
tableView.beginUpdates()
// Modify whatever you need to correspond this change in the data source
tableView.insertSections([indexPathForGestureRecognizer(panGestureRecognizer).section], with: .bottom)
tableView.endUpdates()
This should basically be enough for reordering but you might want to show in table view where the dragged section is. Like having a placeholder at the end of the section in which the stack will be dropped into. That should be relatively easy by simply adding and then moving an extra placeholder cell reusing indexPathForGestureRecognizer
to get a position for it.
Have fun.
UITableView reordering cells in UIViewController - reorder control not showing
To implement row reordering in a UITableView
, you need to implement tableView:canMoveRowAtIndexPath:
and tableView:moveRowAtIndexPath:toIndexPath:
, You might also want to implement tableView:targetIndexPathForMoveFromRowAtIndexPath:toProposedIndexPath:
.
And the most important, the table view must be in edit mode for the reorder controls to appear.
Rearranging between sections in UITableView
I'm not aware of a specific bug, but have you been overriding tableView:targetIndexPathForMoveFromRowAtIndexPath:toProposedIndexPath: explicitly to check the section the row is being attempted to move into? Maybe you're not and the default behavior just happens to work one way and not the other?
Enable UITableView edit only in a specified section
You can achieve this by implementing this delegate method
-(BOOL)tableView:(UITableView *)tableView canMoveRowAtIndexPath:(NSIndexPath *)indexPath {
if (indexPath.section == 3) {
return YES;
} else {
return NO;
}
}
DiffableDataSource - Is there a way to limit reordering only be performed within the same section?
This behaviour isn't a question for your data source. It is a question for your delegate
You can use
collectionView(_:targetIndexPathForMoveFromItemAt:toProposedIndexPath:) to determine whether a move is permitted
func collectionView(_ collectionView: UICollectionView,
targetIndexPathForMoveFromItemAt originalIndexPath: IndexPath,
toProposedIndexPath proposedIndexPath: IndexPath) -> IndexPath {
let sourceSection = sourceIndexPath.section
let destSection = proposedDestinationIndexPath.section
var destination = proposedDestinationIndexPath
if destSection < sourceSection {
destination = IndexPath(item: 0, section: sourceSection)
} else if destSection > sourceSection {
destination = IndexPath(item: self.backingStore[sourceSection].count-1, section: sourceSection)
}
return destination
}
This constrains an item's movement to its own section.
Related Topics
Xcode Debugger Doesn't Print Objects and Shows Nil, When They Aren'T
How to Add a Button to Uinavigationbar
Disable Bitcode for Project and Cocoapods Dependencies with Xcode 7
How to Generate a Barcode from a String in Swift
iOS - Integrating Credit Card Payments
iOS 11 Navigationitem.Titleview Width Not Set
Library Not Found for -Ldoubleconversion
Apple MACh-O Linker Warning "Directory Not Found for Option..."
Nsinternalinconsistencyexception, Reason: Could Not Load Nib in Bundle
Fbsdkaccesstoken Currentaccesstoken Nil After Quitting App
My Swift 4 Uiscrollview with Autolayout Constraints Is Not Scrolling
Swiftui Landmarks App Tutorial Screen Navigates Back When Toggle Favorite
Xcode 6 Save for Enterprise Deployment Does Not Create Plist for IPA Anymore
How to Display the Standard Checkmark on a Uicollectionviewcell