I use a tableView(_:trailingSwipeActionsConfigurationForRowAt:) method in order to add swipe-to-delete gesture in iOS app. It works as expected at iOS 16.2 simulator. But in iOS 13.7 simulator it does not show any actions on swipe.
The method is:
func tableView(_ tableView: UITableView, trailingSwipeActionsConfigurationForRowAt indexPath: IndexPath) -> UISwipeActionsConfiguration? {
let deleteAction = UIContextualAction(style: .destructive, title: "Delete") { [weak self] action, view, handler in
self?.presenter.requestDeletion(at: indexPath.row)
}
let config = UISwipeActionsConfiguration(actions: [deleteAction])
return config
}
I've set breakpoints inside the method and they are not even called on swipe. Swipes at iOS 16.2 trigger the breakpoints.
It's necessary to return true from the tableView(_:canEditRowAt:) data source method, and swipe actions work as expected.
Related
I have an app with multiple view controllers with a tableview in each of them. Each view controller's table have their own specific purpose, but I use the same swipe actions in each table. So far I have just been copying and pasting the same code for trailingSwipeActionsConfigurationForRowAt and leadingSwipeActionsConfigurationForRowAt in each table. This feels wrong and I know there should be a way where I can write the code once and use it throughout the app but I am not sure how to do this.
I have tried to extensions of UITableView but can not seem to use the trailingSwipeActionsConfigurationForRowAt or leadingSwipeActionsConfigurationForRowAt functions in the extension file. What am I missing?
Here's the code for trailingSwipeActionsConfigurationForRowAt which is just swipe to delete:
func tableView(_ tableView: UITableView, trailingSwipeActionsConfigurationForRowAt indexPath: IndexPath) -> UISwipeActionsConfiguration? {
let action = UIContextualAction(style: .destructive, title: "") { (action, view, completionHandler) in
if let item = self.dataSource.itemIdentifier(for: indexPath) {
CoreDataManager.sharedManager.deleteItem(item)
}
completionHandler(true)
}
action.image = UIImage(named: "deleteSymbol")
let configuration = UISwipeActionsConfiguration(actions: [action])
return configuration
}
you declare below function as global function for the project and access any where you want
You can modify function by adding parameter which you want to use when button clicked. just simply add parameter in function and pass data when you call
func getSwipeAction(indexpath : IndexPath)-> UISwipeActionsConfiguration{
let action = UIContextualAction(style: .destructive, title: "") { (action,
view, completionHandler) in
completionHandler(true)
}
action.image = UIImage(named: "deleteSymbol")
let configuration = UISwipeActionsConfiguration(actions: [action])
return configuration
}
You can add these inner code in UITableView extension function and try to use it like that. You have to implement trailingSwipeActionsConfigurationForRowAt or leadingSwipeActionsConfigurationForRowAt in each of your view controllers.
func tableView(_ tableView: UITableView, trailingSwipeActionsConfigurationForRowAt indexPath: IndexPath) -> UISwipeActionsConfiguration? {
return self.YourFunctionNameInExtension()
}
You can define a protocol like BaseTableViewProtocol and in this protocol's extension you can write your code. So when you extend your tableView class from this protocol you can use the function. For example,
protocol BaseTableViewProtocol { }
extension BaseTableViewProtocol {
func trailingSwipeActionsConfigurationForRowAt() {
//Something goes here
}
func leadingSwipeActionsConfigurationForRowAt() {
//Something goes here
}
}
Evening ladies and gentleman,
I am currently getting used to Swift and wanted to start with a little todo app. So far I can add an item and safe it persistently in a context. When an item has been added, it will be shown in a tableview. Now, I want to use a check swipe to strikethrough items, which have been added and safe this information in my context. Deleting using a swipe works perfectly fine.
Has anybody an idea how realize this? I tried to solve it by myself, but couldnt get it done. A similar question has been asked here before, but didnt get a proper answer: Add strikethrough to tableview row with a swipe
func checkAccessoryType(cell: UITableViewCell, isCompleted: Bool) {
if isCompleted {
cell.accessoryType = .checkmark
} else {
cell.accessoryType = .none
}
}
override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
let todo = CoreDataManager.shared.getTodoItem(index: indexPath.row)
todo.completed = !todo.completed
CoreDataManager.shared.safeContext()
if let cell = tableView.cellForRow(at: indexPath){
checkAccessoryType(cell: cell, isCompleted: todo.completed)
}
}
Assuming you are trying to strikethrough the title of your task -- which should be defined as a label -- here is the approach to take:
1- Make sure your label is set to attributed text rather than plain. To do that, go to Main.storyboard, select your label, and inside the attribute inspector, set text to Attributed.
2- Inside your completion block (that is the completion block executed after a swipe) add the following code:
(SWIFT 5)
let attributeString: NSMutableAttributedString = NSMutableAttributedString(string: taskLabel.text)
attributeString.addAttribute(.strikethroughStyle, value: 1, range: NSRange(location: 0, length: taskLabel.text.count))
taskLabel.attributedText = attributeString
Just a little advice: it's always helpful if you add some code when you ask a question.
Let me know if anything doesn't make sense.
Looking at the link that you provided, you need swipe action on your UITableViewCell.
Try looking into:
leadingSwipeActionsConfigurationForRowAt
trailingSwipeActionsConfigurationForRowAt
You need this action to perform the strikethrough label or delete:
func tableView(_ tableView: UITableView,
leadingSwipeActionsConfigurationForRowAt indexPath: IndexPath) -> UISwipeActionsConfiguration?
{
let closeAction = UIContextualAction(style: .normal, title: "Close", handler: { (ac:UIContextualAction, view:UIView, success:(Bool) -> Void) in
print("OK, marked as Closed")
success(true)
})
closeAction.image = UIImage(named: "tick")
closeAction.backgroundColor = .purple
return UISwipeActionsConfiguration(actions: [closeAction])
}
func tableView(_ tableView: UITableView,
trailingSwipeActionsConfigurationForRowAt indexPath: IndexPath) -> UISwipeActionsConfiguration?
{
let modifyAction = UIContextualAction(style: .normal, title: "Update", handler: { (ac:UIContextualAction, view:UIView, success:(Bool) -> Void) in
print("Update action ...")
success(true)
})
modifyAction.image = UIImage(named: "hammer")
modifyAction.backgroundColor = .blue
return UISwipeActionsConfiguration(actions: [modifyAction])
}
Source: https://developerslogblog.wordpress.com/2017/06/28/ios-11-swipe-leftright-in-uitableviewcell/
I'm using SwipeCellKit for my TO DO List app. When the user swipes left it deletes the item, but when the user swipes right I want him to be able to set a reminder on this item, so I've created an actionset a reminder
this action should perform a segue which brings the user to a custom popup with a date picker in it. The problem is that when I click on the button to set a reminder the simulator quits with an uncaught exception. I've already tried to perform deletion from this button it works perfectly, I've also tried to perform another segue to another view controller from this button the simulator quits. Could someone tell me what I'm doing wrong here? Here's my code:
func tableView(_ tableView: UITableView, editActionsForRowAt indexPath: IndexPath, for orientation: SwipeActionsOrientation) -> [SwipeAction]? { if orientation == .left {
guard isSwipeRightEnabled else { return nil }
let setReminder = SwipeAction(style: .default, title: "Set a reminder") { action, indexPath in
self.updateModelByAddingAReminder(at: indexPath)
}
setReminder.image = UIImage(named: "reminder-icon")
return[setReminder]
}else{
let deleteAction = SwipeAction(style: .destructive, title: "Delete") { action, indexPath in
self.updateModel(at: indexPath)
}
// customize the action appearance
deleteAction.image = UIImage(named: "delete-icon")
// return [setReminder, deleteAction]
return [deleteAction]
}
Ok, I found problem in your options for cell.
From doc
The built-in .destructive, and .destructiveAfterFill expansion styles are configured to automatically perform row deletion when the action handler is invoked (automatic fulfillment).
And you need use destructive style for cell in editActionsForRowAt. Or use another options, for example
func tableView(_ tableView: UITableView, editActionsOptionsForRowAt indexPath: IndexPath, for orientation: SwipeActionsOrientation) -> SwipeTableOptions {
var options = SwipeTableOptions()
options.transitionStyle = .border
if orientation == .left{
//or none
options.expansionStyle = .selection
}else{
options.expansionStyle = .destructive
}
return options
}
Hope it's help.
I have a UITableView which in every call has two action.
When I tap on one of them their action not being called and just these action button disappears and cell comes back to its normal place.
their action just being called when I tap and hold for a long time!
how can I fix that?
func tableView(_ tableView: UITableView, editActionsForRowAt indexPath: IndexPath) -> [UITableViewRowAction]? {
let cancel = UITableViewRowAction(style: .destructive, title: "cacel") { action, index in
print("c tapped")
}
let paymentType = UITableViewRowAction(style: .destructive, title: "patmentType") { action, index in
print("p tapped")
}
return [paymentType,cancel]
}
tableView deleagte is set.
I tried code below still bot working :
self.tableView.setEditing(false, animated: true)
and
tableView.isEditing = false
not working yet.
any help please
I've set up a destructive trailing swipe action under iOS 11:
#available(iOS 11.0, *)
override func tableView(_ tableView: UITableView, trailingSwipeActionsConfigurationForRowAt indexPath: IndexPath) -> UISwipeActionsConfiguration? {
let deleteAction = UIContextualAction(style: .destructive, title: "Delete", handler: { (action, view, completionHandler) in
self.deleteRow(atIndexPath: indexPath)
completionHandler(true)
})
// Is it possible here?
//deleteAction.image = UIImage(named: "delete")
let configuration = UISwipeActionsConfiguration(actions: [deleteAction])
return configuration
}
Instead of the "delete" text, I'd like to show the Apple system icon thrash bin found here:
https://developer.apple.com/ios/human-interface-guidelines/icons-and-images/system-icons/
Obviously, I could obtain the icon from somewhere and set it as the image, but I guess there should be a native way to do this.
Thanks for your suggestions!