swiftxcodeuitableviewuiactionsheet

How to trigger an action sheet alert on UITableview cell press on iPadOS


I have some code to bring up an action sheet when a cell in a UITableView is pressed. It works fine on the phone but on the iPad it fails. I have see other people with this problem, needing to reconfigure their action sheet alert code somehow, but all I've seen is for triggering an action sheet on a button press. I've seen this post, but I could not figure out how to implement this provided sample code:

currentPopoverpresentioncontroller.sourceView = cell

Here is my function to show the action sheet:

    func showActionSheet() {
        let alert = UIAlertController(title: "Card Actions", message: "choose action", preferredStyle: .actionSheet)
        alert.addAction(UIAlertAction(title: "Edit", style: .default, handler: { action in
            print("edit tapped")
            self.renameDeckAlert()
    }))
        alert.addAction(UIAlertAction(title: "Delete", style: .destructive, handler: { action in
            self.showDeleteAlert()
    }))
        alert.addAction(UIAlertAction(title: "Cancel", style: .cancel, handler: { action in
    }))
        present(alert, animated: true)
}

And here is where I call the function:

extension EditViewController: UITableViewDelegate {
    func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
        print("You tapped cell #\(indexPath.row)")
        showActionSheet()
        self.editTableView.deselectRow(at: indexPath, animated: true)
    }
}

Can somebody tell me how to bring up an action sheet on iPadOS when a cell in a tableview is pressed?


Solution

  • You can pass in the indexPath of the selected cell to your presenting function. Then, get the cell with cellForRow(at:):

    func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
        showActionSheet(indexPath: indexPath) /// pass in the indexPath
        self.editTableView.deselectRow(at: indexPath, animated: true)
    }
    
    ///                  ↓ add an argument label
    func showActionSheet(indexPath: IndexPath) {
        let alert = UIAlertController(title: "Card Actions", message: "choose action", preferredStyle: .actionSheet)
        alert.addAction(UIAlertAction(title: "Edit", style: .default, handler: { action in
            print("edit tapped")
            
        }))
        alert.addAction(UIAlertAction(title: "Delete", style: .destructive, handler: { action in
            
        }))
        alert.addAction(UIAlertAction(title: "Cancel", style: .cancel, handler: { action in
        }))
        
        /// for iPad
        if let popoverController = alert.popoverPresentationController {
            
            /// get the cell
            let cell = tableView.cellForRow(at: indexPath)
            
            popoverController.sourceView = cell
            popoverController.sourceRect = cell?.bounds ?? CGRect(x: 0, y: 0, width: 50, height: 50)
        }
        
        present(alert, animated: true)
    }
    

    Result:

    iPhone iPad
    Action sheet presented at the bottom of the screen Action sheet presented directly underneath the cell, with an arrow pointing to it