How to present iOS UIActionSheet in Swift?
Your Approach is fine, but you can add UIActionSheet
with other way with ease.
You can add UIActionSheetDelegate
in UIViewController` like
class ViewController: UIViewController ,UIActionSheetDelegate
Set you method like,
@IBAction func downloadSheet(sender: AnyObject)
{
let actionSheet = UIActionSheet(title: "Choose Option", delegate: self, cancelButtonTitle: "Cancel", destructiveButtonTitle: nil, otherButtonTitles: "Save", "Delete")
actionSheet.showInView(self.view)
}
You can get your button index when it clicked like
func actionSheet(actionSheet: UIActionSheet, clickedButtonAtIndex buttonIndex: Int)
{
println("\(buttonIndex)")
switch (buttonIndex){
case 0:
println("Cancel")
case 1:
println("Save")
case 2:
println("Delete")
default:
println("Default")
//Some code here..
}
}
Update 1: for iOS8+
//Create the AlertController and add Its action like button in Actionsheet
let actionSheetControllerIOS8: UIAlertController = UIAlertController(title: "Please select", message: "Option to select", preferredStyle: .ActionSheet)
let cancelActionButton = UIAlertAction(title: "Cancel", style: .cancel) { _ in
print("Cancel")
}
actionSheetControllerIOS8.addAction(cancelActionButton)
let saveActionButton = UIAlertAction(title: "Save", style: .default)
{ _ in
print("Save")
}
actionSheetControllerIOS8.addAction(saveActionButton)
let deleteActionButton = UIAlertAction(title: "Delete", style: .default)
{ _ in
print("Delete")
}
actionSheetControllerIOS8.addAction(deleteActionButton)
self.present(actionSheetControllerIOS8, animated: true, completion: nil)
UIActionSheet with swift
You never set the action sheet's delegate:
myActionSheet = UIActionSheet()
myActionSheet.delegate = self
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!;
}
How to create a general method for multiple UIActionSheet in Swift
Solution 1:
If your AlertViewController
's actions will always have segue to perform you can significantly reduce duplication like below using struct and variadic parameters:
struct Option {
var name: String
var segueIdentifier: String
}
func configureActionSheet(options: Option...) {
let actionSheet = UIAlertController(title: nil, message: nil, preferredStyle: .actionSheet)
let cancel = UIAlertAction(title: "Cancel", style: .cancel, handler: nil)
actionSheet.addAction(cancel)
for option in options {
let currentOption = UIAlertAction(title: option.name, style: .default) { action in
self.performSegue(withIdentifier: option.segueIdentifier, sender: self)
}
actionSheet.addAction(currentOption)
}
if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiom.pad ){
actionSheet.popoverPresentationController?.sourceView = self.view
actionSheet.popoverPresentationController?.sourceRect = CGRect(x: self.view.bounds.midX, y: self.view.bounds.midY, width: 0, height: 0)
actionSheet.popoverPresentationController?.permittedArrowDirections = []
}
self.present(actionSheet, animated: true, completion: nil)
}
func showMenu1() {
let option1 = Option(name: "Option 1", segueIdentifier: "optionOne")
let option2 = Option(name: "Option 2", segueIdentifier: "optionTwo")
self.configureActionSheet(options: option1, option2)
}
Solution 2:
If your AlertViewController
's action will always be different then there is not much you can do but still avoid duplication as follows:
func configureActionSheet() -> UIAlertController {
let actionSheet = UIAlertController(title: nil, message: nil, preferredStyle: .actionSheet)
let cancel = UIAlertAction(title: "Cancel", style: .cancel, handler: nil)
actionSheet.addAction(cancel)
if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiom.pad ){
actionSheet.popoverPresentationController?.sourceView = self.view
actionSheet.popoverPresentationController?.sourceRect = CGRect(x: self.view.bounds.midX, y: self.view.bounds.midY, width: 0, height: 0)
actionSheet.popoverPresentationController?.permittedArrowDirections = []
}
return actionSheet
}
func showFirstMenu() {
let optionOne = UIAlertAction(title: "Option 1", style: .default) { action in
self.performSegue(withIdentifier: "optionOne", sender: self)
}
let optionTwo = UIAlertAction(title: "Option 2", style: .default) { action in
self.performSegue(withIdentifier: "optionTwo", sender: self)
}
let actionSheet = configureActionSheet()
actionSheet.addAction(optionOne)
actionSheet.addAction(optionTwo)
self.present(actionSheet, animated: true, completion: nil)
}
How to load JSON array data into UIActionSheet button title using Swift
Just loop and add action to ActionSheet
@IBAction func ClickAction(_ sender: Any) {
let actionSheetAlertController: UIAlertController = UIAlertController(title: nil, message: nil, preferredStyle: .actionSheet)
for title in self.titleData {
let action = UIAlertAction(title: title.status, style: .default) { (action) in
print("Title: \(title.id)")
}
let icon = UIImage.init(named: title.icon)
action.setValue(icon, forKey: "image")
action.setValue(CATextLayerAlignmentMode.left, forKey: "titleTextAlignment")
actionSheetAlertController.addAction(action)
}
let cancelActionButton = UIAlertAction(title: "Cancel", style: .cancel, handler: nil)
actionSheetAlertController.addAction(cancelActionButton)
self.present(actionSheetAlertController, animated: true, completion: nil)
}
How to create a reusable UIAlert ActionSheet as an UIViewController extension?
I have find out the best way to add an action sheet with cancel and as much action as needed.
Create an UIViewController extension with type alias:
//MARK: - Alert that shows an action sheet with cancel
extension UIViewController {
typealias AlertAction = () -> ()
typealias AlertButtonAction = (ActionSheetLabel, AlertAction)
func showActionSheetWithCancel(titleAndAction: [AlertButtonAction]) {
let actionSheet = UIAlertController(title: nil, message: nil, preferredStyle: .actionSheet)
for value in titleAndAction {
actionSheet.addAction(UIAlertAction(title: value.0.rawValue, style: .default, handler: {
(alert: UIAlertAction!) -> Void in
value.1()
}))
}
actionSheet.addAction(UIAlertAction(title: ActionSheetLabel.cancel.rawValue, style: .cancel, handler: nil))
self.present(actionSheet, animated: true, completion: nil)
}
}
Then, in the class or other place where you want to use it, add the method this way:
//MARK: - UIAlert action sheet title
enum ActionSheetLabel: String {
case camera = "Camera"
case photoLibrary = "Album"
case cancel = "Cancel"
}
//MARK: - Class example where to use the action sheet action
class CameraHandler {
fileprivate let currentVC: UIViewController!
func openCamera() {
// Open user camera
}
func openPhotoLibrary() {
// Open user photo library
}
// Method example of this action sheet
func showActionSheetWithCameraAndLibrary(vc: UIViewController) {
//This is the way to use the extension
vc.showActionSheetWithCancel(titleAndAction: [
(ActionSheetLabel.camera, { [weak self] in self?.openCamera() }),
(ActionSheetLabel.photoLibrary, { [weak self] in self?.openPhotoLibrary() })
])
}
}
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
}
}
How to add UIActionSheet button check mark?
Note that the solution can crash in a future update to iOS. I'm
accessing undocumented private APIs. Such solutions are very fragile. Please see the comments below.
Finally I got the answer by using UIAlertController:
UIAlertController *customActionSheet = [UIAlertController alertControllerWithTitle:nil message:nil preferredStyle:UIAlertControllerStyleActionSheet];
UIAlertAction *firstButton = [UIAlertAction actionWithTitle:@"First Button" style:UIAlertActionStyleDefault handler:^(UIAlertAction * action) {
//click action
}];
[firstButton setValue:[UIColor blackColor] forKey:@"titleTextColor"];
[firstButton setValue:[UIColor blackColor] forKey:@"imageTintColor"];
[firstButton setValue:@true forKey:@"checked"];
UIAlertAction *secondButton = [UIAlertAction actionWithTitle:@"Second Button" style:UIAlertActionStyleDefault handler:^(UIAlertAction * action) {
//click action
}];
[secondButton setValue:[UIColor blackColor] forKey:@"titleTextColor"];
UIAlertAction *cancelButton = [UIAlertAction actionWithTitle:@"Cancel" style:UIAlertActionStyleCancel handler:^(UIAlertAction *action){
//cancel
}];
[cancelButton setValue:[UIColor blackColor] forKey:@"titleTextColor"];
[customActionSheet addAction:firstButton];
[customActionSheet addAction:secondButton];
[customActionSheet addAction:cancelButton];
[self presentViewController:customActionSheet animated:YES completion:nil];
And this is the result:
Handling events on UIActionSheet in SWIFT
You could try something like:
var actionSheet = UIAlertController(title: "Publish this Image ?", message: nil, preferredStyle: UIAlertControllerStyle.ActionSheet)
actionSheet.addAction(UIAlertAction(title: "Tweet", style: UIAlertActionStyle.Default, handler: { (ACTION :UIAlertAction!)in
//your code here...
}))
actionSheet.addAction(UIAlertAction(title: "WhatsApp", style: UIAlertActionStyle.Default, handler: { (ACTION :UIAlertAction!)in
//your code here...
}))
actionSheet.addAction(UIAlertAction(title: "Cancel", style: UIAlertActionStyle.Cancel, handler: nil))
self.presentViewController(actionSheet, animated: true, completion: nil)
Related Topics
When Should I Use Anyobject Insted of Uibutton in Swift
Value of Type 'Error' Has No Member 'Code'
How to Add a Ibaction to a Button Programmatically in Swift 4
How to Create a Pfquerytableviewcontroller with Parse in Swift
Storyboard Reference to Cocoapods Storyboard Seems Broken
Openurl in Appdelegate Conversion Error Nsstring -> String (Swift & iOS8)
iOS Swift 2 Record Video Avcapturesession
Correct Way to Layout Swiftui (Similar to Autolayout)
Infinite Scroll on iOS with Swift
Make Skspritenode Subclass Using Swift
Uidocumentinteractioncontroller() Swift
Uisearchcontroller Searchbar Delegate Not Working