UITableViewRowAction vs UISwipeActionsConfiguration

It does basically the same, but swipe actions are available since iOS 11 was released and have some new features:

  • You are able to set actions for trailing swipe as well as for leading swipe
  • You can set image of action action.image = UIImage(...). If there is enough space it shows image as well as title enter image description here

Also, you should use swipe actions because they are preferred and in the future updates UITableViewRowActions will be deprecated how UITableView header comment can tell us:

Use -tableView:trailingSwipeActionsConfigurationForRowAtIndexPath: instead of this method, which will be deprecated in a future release.


Here is the code which is working for me

internal func tableView(_ tableView: UITableView, trailingSwipeActionsConfigurationForRowAt indexPath: IndexPath) -> UISwipeActionsConfiguration? {

   // let delete = UITableViewRowAction(style: .destructive, title: "Delete") { (action, indexPath) in
    let contextItem = UIContextualAction(style: .destructive, title: "") {  (contextualAction, view, boolValue) in
    // delete item at indexPath
       //if self.isfilterenabled == true {
         //   return
        //}


        if self.isfilterenabled == true {
            //entryFilter.filteredEntries[indexPath.row]
            self.entryFilter.filteredEntries.remove(at: indexPath.row)
        } else {
            self.data.remove(at: indexPath.row)
        }

        self.table.deleteRows(at: [indexPath], with: .fade)
        self.save()
    }



    //let share = UITableViewRowAction(style: .normal, title: "SavePDF") { (action, indexPath) in
        // share item at indexPath
    let contextItemSave = UIContextualAction(style: .normal, title: "") {  (contextualAction, view, boolValue) in





        let alert  = UIAlertController(title: "Done! ", message: "PDF has been saved " ,preferredStyle: .alert)

        let okAction = UIAlertAction(title: "OK ", style: .default, handler: nil)
        alert.addAction(okAction)

        alert.popoverPresentationController?.sourceView = self.view // so that iPads won't crash

        // exclude some activity types from the list (optional)
        //activityViewController.excludedActivityTypes = [ UIActivityTypeAirDrop, UIActivityTypePostToFacebook ]

        // present the view controller
        self.present(alert, animated: true, completion: nil)
        // present(alert, animated : true, completion : nil )

    }

   // share.backgroundColor = UIColor.blue

    contextItemSave.image = UIImage(named:"PDF.jpg")
    contextItem.image = UIImage(named:"delete.jpg")
    let swipeActions = UISwipeActionsConfiguration(actions: [contextItem,contextItemSave])

    return swipeActions
    //return [delete, share]
}`

I have created an extension for UISwipeActionsConfiguration which you can use if you have a sizing issue with your image. Basically, the idea is to create an Attributed String from the image and the text and set it to label and create an image from that label. And append it to UIContextualAction's image property.

extension UISwipeActionsConfiguration {

    public static func makeTitledImage(
        image: UIImage?,
        title: String,
        textColor: UIColor = .white,
        font: UIFont = .systemFont(ofSize: 14),
        size: CGSize = .init(width: 50, height: 50)
    ) -> UIImage? {
        
        /// Create attributed string attachment with image
        let attachment = NSTextAttachment()
        attachment.image = image
        let imageString = NSAttributedString(attachment: attachment)
        
        /// Create attributed string with title
        let text = NSAttributedString(
            string: "\n\(title)",
            attributes: [
                .foregroundColor: textColor,
                .font: font
            ]
        )
        
        /// Merge two attributed strings
        let mergedText = NSMutableAttributedString()
        mergedText.append(imageString)
        mergedText.append(text)
        
        /// Create label and append that merged attributed string
        let label = UILabel(frame: CGRect(x: 0, y: 0, width: size.width, height: size.height))
        label.textAlignment = .center
        label.numberOfLines = 2
        label.attributedText = mergedText
        
        /// Create image from that label
        let renderer = UIGraphicsImageRenderer(bounds: label.bounds)
        let image = renderer.image { rendererContext in
            label.layer.render(in: rendererContext.cgContext)
        }
        
        /// Convert it to UIImage and return
        if let cgImage = image.cgImage {
            return UIImage(cgImage: cgImage, scale: UIScreen.main.scale, orientation: .up)
        }
        
        return nil
    }
}

And you can use it like this;

public func tableView(
        _ tableView: UITableView,
        trailingSwipeActionsConfigurationForRowAt indexPath: IndexPath
    ) -> UISwipeActionsConfiguration? 
{
        let deleteAction = UIContextualAction(
            style: .normal,
            title:  nil,
            handler: { [weak self] (_, _, success: (Bool) -> Void) in
                success(true)
                print("Your action in here")
            }
        )
        
        deleteAction.image = UISwipeActionsConfiguration.makeTitledImage(
            image: UIImage(named: "delete_icon"),
            title: "Delete")
        )
        deleteAction.backgroundColor = .orange
        return UISwipeActionsConfiguration(actions: [deleteAction])
}

Tags:

Ios

Swift