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:
iPhone | iPad |
---|---|
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
}
}
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
Cannot Assign Value of Type 'Menuview' to Type 'some View'
Arkit: Place Object on a Plane Doesn't Work Properly
Why Are Image Views Sometimes Not Appearing in Collection View Cells
Tab Bar Item Icons Appear Darker
How to Center Nspopover When Using Swiftui
How to Custom The Image of Mkannotation Pin
Restrictions Around Protocols and Generics in Swift
Cllocationmanager and Tvos - Requestwheninuseauthorization() Not Prompting
In App Purchase in Skscene Not Working
Remove Cell When Button Pressed Inside Cell Customtableviewcell
How to Cut a Hole in a Sprite Image or Texture to Show What Is Behind It Using Spritekit in Swift
Prepareforsegue from a UIbutton in a Custom Prototype Cell