Uiactionsheet with Swift

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
}
}

Demo App

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:

UIActionSheet button check mark

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



Leave a reply



Submit