I am trying to learn Swift, but there is a problem in my project that drives me nuts.
I have a working list of data in a ViewController fed by parse.com. I managed to implement a swipe-feature that reveals buttons for both deleting and editing. That is working fine. Now I want the user to be able to reorder the cells. So I successfully implemented a button to put the table into editing-mode. My 2 problems with that are:
When I enter edit-mode I just want to be able to reorder the cells since editing and deleting is done via swipe (via "tableView(tableView: UITableView, editActionsForRowAtIndexPath indexPath: NSIndexPath)". How can I achive that the user doesn't see the 2 buttons for deleting and editing when in editing-mode and touching the delete-circle that is provided automatically?
Is it possible to remove the delete-circle altogether? Using "UITableViewCellEditingStyle.None" also disables the swipe-functionality.
Thanks in advance!
To avoid the round red delete button that appears when you put set UITableView isEditing to true at the left and does nothing when you click it, the minimum that worked for me was this (Swift 4, iOS 11)
// Avoid the round red delete button on the left of the cell:
func tableView(_ tableView: UITableView, shouldIndentWhileEditingRowAt indexPath: IndexPath) -> Bool {
return false
}
func tableView(_ tableView: UITableView, editingStyleForRowAt indexPath: IndexPath) -> UITableViewCellEditingStyle {
return .none
}
I also have these functions, which probably interact:
func tableView(_ tableView: UITableView, canEditRowAt indexPath: IndexPath) -> Bool {
return savedTempTable.isEditing
}
// Including this function in the delegate enable left-swipe deleting
func tableView(_ tableView: UITableView, commit editingStyle: UITableViewCellEditingStyle, forRowAt indexPath: IndexPath)
{
if editingStyle == .delete {
savedConversions.remove(at: indexPath.row)
}
}
// Including this function enables reordering
func tableView(_ tableView: UITableView, moveRowAt sourceIndexPath: IndexPath,to destinationIndexPath: IndexPath)
{
let elem = savedConversions.remove(at: sourceIndexPath.row)
savedConversions.insert(elem, at: destinationIndexPath.row)
}
override func tableView(_ tableView: UITableView, editingStyleForRowAt indexPath: IndexPath) -> UITableViewCellEditingStyle {
return .none
}
override func tableView(_ tableView: UITableView, shouldIndentWhileEditingRowAt indexPath: IndexPath) -> Bool {
return false
}
Although people can delete a row through swipe the delete-button in editing mode should not be removed. People may not know about the swipe gesture and by removing the delete button (which they already expect in editing mode) the app becomes more difficult to use.
If you really want to remove the delete button then you have to implement the delegate method tableView(_:editingStyleForRowAtIndexPath:). There you can return .None while the screen is in editing mode and .Delete while the screen is not.
To enable reordering you have to implement the data source methods tableView(_:canMoveRowAtIndexPath:) and tableView(_:moveRowAtIndexPath:toIndexPath:).
You follow this way to remove the delete Icon while editing:
-(UITableViewCellEditingStyle)tableView:(UITableView *)tableView editingStyleForRowAtIndexPath:(NSIndexPath *)indexPath{
return UITableViewCellAccessoryNone;
}
Related
I'm trying to play a reorder animation that should be called by the methods below, I guess
func tableView(_ tableView: UITableView, canMoveRowAt indexPath: IndexPath) -> Bool {
true
}
func tableView(_ tableView: UITableView, moveRowAt sourceIndexPath: IndexPath, to destinationIndexPath: IndexPath) {
}
But for some reason, no animation followed. Most likely, I missed something, how exactly to trigger the animation of changing the order of the cells.
I found the missing component. The reason for which the animation of moving cells did not start. It's the lack of a setting:
tableView.isEditing = true
I am currently working on a solution where I need to have a UITableView by default in reorder mode without having a delete button but could enable the delete button when necessary. I am just curious if this is even achievable in iOS? If so what should be my approach for this?
In my opinion your table view should always be in edit mode.
To make the reorder controls appear you should implement UITableViewDataSource methods
tableView(_ tableView: UITableView, canMoveRowAt indexPath: IndexPath) -> Bool
and
tableView(_ tableView: UITableView, moveRowAt sourceIndexPath: IndexPath, to destinationIndexPath: IndexPath)
If you don't want the delete button to be displayed you can do that by implementing
tableView(_ tableView: UITableView, editingStyleForRowAt indexPath: IndexPath) -> UITableViewCell.EditingStyle
and return .none by default or .delete when you want to have the button displayed.
I have a UITableViewCell where I have implemented leadingSwipeActionsConfigurationForRowAt indexPath to allow users to drag right on cells to add them to their favorites. However, in doing so the option for dragging left to delete also appeared. I don't want these cells to be able to be deleted. Is there a way to implement swipe actions without the delete action appearing?
Try this
func tableView(_ tableView: UITableView, canEditRowAt indexPath: IndexPath) -> Bool {
return false
}
Edit
func tableView(_ tableView: UITableView, trailingSwipeActionsConfigurationForRowAt indexPath: IndexPath) -> UISwipeActionsConfiguration? {
let swipeAction = UISwipeActionsConfiguration(actions: [])
swipeAction.performsFirstActionWithFullSwipe = false // This is the line which disables full swipe
return swipeAction
}
I have implemented two custom cells in the tableview.Now I want to replace these two custom cells with one another. How to achieve this?
Implement following tableview methods and write your code in it
func tableView(_ tableView: UITableView, canMoveRowAt indexPath: IndexPath) -> Bool {
// return boolean value for a specific or all cells, you want to enable movement
}
func tableView(_ tableView: UITableView, moveRowAt sourceIndexPath: IndexPath, to destinationIndexPath: IndexPath) {
// Handle array element movement along with your row/cell
}
Share your full source code better help
If you would like to reorder rows in UITableView. Take a look at two delegates that are implemented in the UITableView.
They are: tableView:canMoveRowAtIndexPath: and moveRowAtIndexPath:toIndexPath:.
Also take a look at tutorial that show how it is possible to implement.
Along with tableview delegates, use moveRow(at: <IndexPath>, to: <IndexPath>), to move your row programatically (automatically), without user interaction.
tblTabel.moveRow(at: <IndexPath>, to: <IndexPath>)
// Tableview Delegates
func tableView(_ tableView: UITableView, canMoveRowAt indexPath: IndexPath) -> Bool {
// return boolean value for a specific or all cells, you want to enable movement
}
func tableView(_ tableView: UITableView, moveRowAt sourceIndexPath: IndexPath, to destinationIndexPath: IndexPath) {
// Handle array element movement along with your row/cell
}
When I click on Edit button in my screen i change my TableView to edit mode and set the edit style as check box by doing this
func tableView(_ tableView: UITableView, editingStyleForRowAt indexPath: IndexPath) -> UITableViewCellEditingStyle {
return UITableViewCellEditingStyle.init(rawValue: 3)!
}
now I need programatically pre check some of the entries.
How can i Make some of the cells as checked?
I know in
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell
I have to set the edit style which marks it as checked.
I finally figured it out.
Setting the Checkbox in an table view is equivalent to selecting the cell.
so all you need to do is mark the sell as selected, nothing to do with the Edit style
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "MyCell", for: indexPath) as! MyCell
let item = self.items[indexPath.row]
cell.setup(item: item)
cell.setSelected(true, animated: true) // Provided your cell is already in check box edit mode, then this makes it CHECK ON
return cell
}
By the way. I saw an explanation in similar question here (on SO) that you should not use this:
return UITableViewCellEditingStyle.init(rawValue: 3)!
Because it's not public API and if Apple changes this value, application will stop working properly. The same behaviour can be reached simply by enabling Multiple selection during editing:
You can check it easily by setting breakpoint on your overridden method
func tableView(_ tableView: UITableView, editingStyleForRowAt indexPath: IndexPath) -> UITableViewCellEditingStyle {
return UITableViewCellEditingStyle.init(rawValue: 3)!
}
And enable editing during running the app with Multiple selection during editing and without it. You will see that if Multiple selection during editing is enabled, this method will not be called at all.