Showing Action Sheet in The Custom Cell in Swift

showing action sheet in the custom cell in Swift

In your custom cell's swift file, write a protocol to be conformed by your viewContoller,

// your custom cell's swift file

protocol CustomCellDelegate {
func showActionSheet()
}

class CustomTableViewCell : UITableViewCell {
var delegate: CustomCellDelegate?

// This is the method you need to call when button is tapped.
@IBAction func buttonTapped() {

// When the button is pressed, buttonTapped method will send message to cell's delegate to call showActionSheet method.
if let delegate = self.delegate {
delegate.showActionSheet()
}
}
}

// Your tableViewController
// it should conform the protocol CustomCellDelegate

class MyTableViewController : UITableViewController, CustomCellDelegate {

// other code

override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {

let cell = tableView.dequeueReusableCellWithIdentifier("CustomCellReuseIdentifier", forIndexPath: indexPath)

// configure cell

cell.delegate = self

return cell
}

// implement delegate method
func showActionSheet() {

// show action sheet

}
}

Make sure your view controller conforms CustomCellDelegate protocol and implements showActionSheet() method.

Assign your viewContoller as delegate of the custom cell when creating your cells in cellForRowAtIndexPath dataSource method.

You can present your new view controller from the showActionSheet method in viewController.

Displaying action sheet when tableview cell is tapped

You're almost there, make sure you add your deleteButton-action as well and present the alertController using present(alertController, animated: true, completion: nil)

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

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:















iPhoneiPad
Action sheet presented at the bottom of the screenAction sheet presented directly underneath the cell, with an arrow pointing to it

Swift - How to update custom cell label from UIActionSheet

You need to update your model data (and subsequently your cell label) once the user has made a selection from the alert. The alert choice is made asynchronously. There are a couple of common approaches you could use. One is delegation. The other is to pass a completion handler closure. The second is more Swifty and is what I will use.

First, you have an error in your cellForItemAt - It will be called for each cell, so you shouldn't have a for loop - You need to access the required element based on the IndexPath.item. This is one function where you typically will use a force downcast and a force unwrap, since the cell class needs to be registered and your numberOfItems function should return 0 if you have no entries (or no player) -

func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {

let cell = collectionView.dequeueReusableCell(withReuseIdentifier: DIISDetailCell.reuseIdentifier, for: indexPath) as! DIISDetailCell
let entry = player!.entries[indexPath.item]
cell.eventName.text = entry.injuryIllnessName
cell.eventDate.text = entry.statusDate.formatted()
cell.eventType.text = entry.status
cell.modifiedBy.text = entry.modifiedBy ?? "Modified By Goes Here"

return cell
}

You can simplify your dailyInjuryIllnessActionSheet code a little by using an array for the options. For simplicity I have declared the array in the function, but it should probably be passed in from some other information source.

Add a completion handler parameter to this function to pass the selected option back to the caller:

func dailyInjuryIllnessActionSheet(completion:((String?)->Void)?=nil) {

let options = ["Available for Full Participation",
"Available for Limited Participation",
"Not Available For Participation",
"Close Injury / Illness"
]
let alert = UIAlertController(title: "Title", message: "Select an Option", preferredStyle: .actionSheet)

for option in options {
alert.addAction(UIAlertAction(title: option, style: .default, handler: { action in
completion?(option)
}))
}
alert.addAction(UIAlertAction(title: "Cancel", style: .destructive, handler: { action in
completion?(nil)
}))
present(alert, animated: true, completion: nil)
}

Now you can pass a completion handler when you call dailyInjuryIllnessActionSheet to update your model and reload the item:

func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
dailyInjuryIllnessActionSheet() { selectedOption in {
guard let selectedOption = selectedOption else {
return
}
player!.entries[indexPath.item].status = selectedOption
collectionView.reloadItems(at:[indexPath])
}

}

Swift: How to create UIActionSheet with click on button UITableVieCell

Try this and do some changes in UserTableViewCell

class UserTableViewCell: UITableViewCell {
weak var myVC : UIViewController?
@IBAction func btnMenu(_ sender: UIButton) {
//here I want to execute the UIActionSheet
let actionsheet = UIAlertController(title: nil, message: nil, preferredStyle: UIAlertControllerStyle.actionSheet)

actionsheet.addAction(UIAlertAction(title: "Take a Photo", style: UIAlertActionStyle.default, handler: { (action) -> Void in
}))

actionsheet.addAction(UIAlertAction(title: "Choose Exisiting Photo", style: UIAlertActionStyle.default, handler: { (action) -> Void in
}))
actionsheet.addAction(UIAlertAction(title: "Cancel", style: UIAlertActionStyle.cancel, handler: { (action) -> Void in

}))
myVC?.present(actionsheet, animated: true, completion: nil)
}
}

And modify this method

func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "userCell", for: indexPath) as? UserTableViewCell;

cell?.view(with: users[indexPath.row]);
cell?.myVC = self
return cell!;
}

Pass value with action sheet button

On button action you are showing the ActionSheet and you want that button's index on prepareforSegue method, so you need to store the IndexPath of tapped button on the action of button and then present the ActionSheet for that declare one instance of type IndexPath and use it inside your button action.

var selectedIndexPath = IndexPath()

@IBAction func buttonTapped(_ sender: UIButton) {
let point = tableView.convert(CGPoint.zero, from: sender)
if let indexPath = tableView.indexPathForRow(at: point) {
self.selectedIndexPath = indexPath
//Add code for presenting ActionSheet
}
}

override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if segue.identifier == "editPost" {
let dest = segue.destination as! EditPostViewController
dest.selectedPost = postsArray[self.selectedIndexPath.row]
}
}

Customised UIActionSheet

If you really want to do something like that you could give this a go. I can't guarantee it'll be approved by Apple and honestly, it's just not recommended from a UI and Apple HIG perspective.

Keep in mind UIActionSheet has been deprecated and it's recommended to use UIAlertController with a preferredStyle of .ActionSheet so that's what this example is going to use.

import UIKit

class ViewController: UIViewController {

override func viewDidAppear(animated: Bool) {
super.viewDidAppear(animated)

let controller = SwiftDemoAlertController(title: nil, message: nil, preferredStyle: .ActionSheet)
controller.addAction(UIAlertAction(title: "Reset to default", style: .Destructive, handler: nil))
controller.addAction(UIAlertAction(title: "Save", style: .Default, handler: nil))

self.presentViewController(controller, animated: true, completion: nil)
}

override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
}

override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}

}

class SwiftDemoAlertController: UIAlertController, UITableViewDataSource {

private var controller : UITableViewController

override init(nibName nibNameOrNil: String?, bundle nibBundleOrNil: NSBundle?) {
controller = UITableViewController(style: .Plain)
super.init(nibName: nibNameOrNil, bundle: nibBundleOrNil)
controller.tableView.registerClass(UITableViewCell.self, forCellReuseIdentifier: "cell")
controller.tableView.dataSource = self
controller.tableView.addObserver(self, forKeyPath: "contentSize", options: [.Initial, .New], context: nil)
self.setValue(controller, forKey: "contentViewController")
}

override func observeValueForKeyPath(keyPath: String?, ofObject object: AnyObject?, change: [String : AnyObject]?, context: UnsafeMutablePointer<Void>) {
guard keyPath == "contentSize" else {
return
}

controller.preferredContentSize = controller.tableView.contentSize
}

required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}

deinit {
controller.tableView.removeObserver(self, forKeyPath: "contentSize")
}

func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return 6
}

func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCellWithIdentifier("cell")!

switch(indexPath.row) {
case 0:
cell.textLabel?.text = "Upcoming activities"
let switchView = UISwitch(frame: CGRectZero)
cell.accessoryView = switchView
switchView.setOn(true, animated: false)
break
case 1:
cell.textLabel?.text = "Past activities"
let switchView = UISwitch(frame: CGRectZero)
cell.accessoryView = switchView
switchView.setOn(false, animated: false)
break
case 2:
cell.textLabel?.text = "Activities where I am admin"
let switchView = UISwitch(frame: CGRectZero)
cell.accessoryView = switchView
switchView.setOn(true, animated: false)
break
case 3:
cell.textLabel?.text = "Attending"
let switchView = UISwitch(frame: CGRectZero)
cell.accessoryView = switchView
switchView.setOn(true, animated: false)
break
case 4:
cell.textLabel?.text = "Declined"
let switchView = UISwitch(frame: CGRectZero)
cell.accessoryView = switchView
switchView.setOn(true, animated: false)
break
case 5:
cell.textLabel?.text = "Not responded"
let switchView = UISwitch(frame: CGRectZero)
cell.accessoryView = switchView
switchView.setOn(true, animated: false)
break
default:
fatalError()
}

return cell
}
}

Demo App

Using Collection View in ActionSheet to show photos

Replace:

self.collectionView = UICollectionView(frame: CGRect(x: 0, y: 0, width: alert.view.bounds.size.width - viewmargin * 4.0, height: 100), collectionViewLayout: layout)

with:

collectionView = UICollectionView(frame: CGRect.zero, collectionViewLayout: layout)

With the old one!!
And u have 2 of this , set the first one to CGRect.zero

How to activate action sheet buttons with swift?

You can do it this way:

let Reportbutton = UIAlertAction(title: "E-Mail", style: UIAlertActionStyle.Default) { (alert) -> Void in

//Your code
}

Here is the example code for you to send E-mail:

import UIKit
import MessageUI

class TableViewController: UITableViewController, MFMailComposeViewControllerDelegate {

var tabledata = ["1","2","3","4"]
override func viewDidLoad() {
super.viewDidLoad()
}
// MARK: - Table view data source

override func numberOfSectionsInTableView(tableView: UITableView) -> Int {

return 1
}

override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {

return tabledata.count
}

override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCellWithIdentifier("Cell", forIndexPath: indexPath) as UITableViewCell

// Configure the cell...
cell.textLabel?.text = tabledata[indexPath.row]
return cell
}

override func tableView(tableView: UITableView,editActionsForRowAtIndexPath indexPath: NSIndexPath) -> [AnyObject]? {

var ReportAction = UITableViewRowAction(style: .Default, title: "Report User", handler: {(action: UITableViewRowAction! , indexPath:NSIndexPath!) -> Void in

let ReportMenu = UIAlertController(title: nil, message: "Report using", preferredStyle: UIAlertControllerStyle.ActionSheet)
let Reportbutton = UIAlertAction(title: "E-Mail", style: UIAlertActionStyle.Default) { (alert) -> Void in

self.displayMailComposerSheet()
}
ReportMenu.addAction(Reportbutton)
self.presentViewController(ReportMenu, animated: true, completion: nil)

})

var DeleteButton = UITableViewRowAction(style: UITableViewRowActionStyle.Default , title: "Delete", handler: { (action:UITableViewRowAction!, indexPath:NSIndexPath!) -> Void in

self.tabledata.removeAtIndex(indexPath.row)

self.tableView.deleteRowsAtIndexPaths([indexPath], withRowAnimation: .Fade)

}
)
return [DeleteButton , ReportAction]
}

override func tableView(tableView: UITableView, canEditRowAtIndexPath indexPath: NSIndexPath) -> Bool {
return true
}

override func tableView(tableView: UITableView, commitEditingStyle editingStyle: UITableViewCellEditingStyle, forRowAtIndexPath indexPath: NSIndexPath) {
switch editingStyle {
case .Delete:

// remove the deleted item from the model
self.tabledata.removeAtIndex(indexPath.row)
// remove the deleted item from the `UITableView`
self.tableView.deleteRowsAtIndexPaths([indexPath], withRowAnimation: .Fade)
default:
return
}
}

func displayMailComposerSheet(){

//vars
var controller = MFMailComposeViewController()
controller.mailComposeDelegate = self

//set
controller.navigationBar.tintColor = UIColor.whiteColor()

//set
UINavigationBar.appearance().translucent = false
UINavigationBar.appearance().barTintColor = UIColor.whiteColor()
UINavigationBar.appearance().tintColor = UIColor.blackColor()
var attributes = NSDictionary(objectsAndKeys: UIFont(name: "HelveticaNeue-Light", size: 20)!,NSFontAttributeName, UIColor.whiteColor(), NSForegroundColorAttributeName)
UINavigationBar.appearance().titleTextAttributes = attributes

//set
var toRecipients = NSArray(object: "support@YourDomain.com")
controller.setToRecipients(toRecipients)
controller.setSubject("App Support")

//show
presentViewController(controller, animated: true, completion: {

UIApplication.sharedApplication().setStatusBarStyle(UIStatusBarStyle.Default, animated: true)
})
}
}


Related Topics



Leave a reply



Submit