How to add UIActionSheet button check mark?

14,442

Solution 1

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

Solution 2

Swift Version: 4.1

I came across this implementation using creating extension over UIAlertController.

extension UIAlertController {
static func actionSheetWithItems<A : Equatable>(items : [(title : String, value : A)], currentSelection : A? = nil, action : @escaping (A) -> Void) -> UIAlertController {
    let controller = UIAlertController(title: nil, message: nil, preferredStyle: .actionSheet)
    for (var title, value) in items {
        if let selection = currentSelection, value == selection {
            // Note that checkmark and space have a neutral text flow direction so this is correct for RTL
            title = "✔︎ " + title
        }
        controller.addAction(
            UIAlertAction(title: title, style: .default) {_ in
                action(value)
            }
        )
    }
    return controller
}

}

Implementation:

   func openGenderSelectionPopUp() {
     let selectedValue = "Men" //update this for selected value
     let action = UIAlertController.actionSheetWithItems(items: [("Men","Men"),("Women","Women"),("Both","Both")], currentSelection: selectedValue, action: { (value)  in
        self.lblGender.text = value
     })
     action.addAction(UIAlertAction.init(title: ActionSheet.Button.cancel, style: UIAlertActionStyle.cancel, handler: nil))
     //Present the controller
     self.present(action, animated: true, completion: nil)
}

Final Result:

Select Gender

Hope that helps!

Thanks

Solution 3

Swift implementation:

class Controller: UIViewController {

    var isFirstButtonChecked = true

    @IBAction func buttonTapped(_ sender: UIButton?) {
        let firstButton = UIAlertAction(title: "First Button", style: .default, handler: { [unowned self] _ in
            self.isFirstButtonChecked = true
            print("First Button tapped")
        })
        //Here's the main magic; it's called Key-Value Coding, or KVC:
        firstButton.setValue(isFirstButtonChecked, forKey: "checked")

        let secondButton = UIAlertAction(title: "Second Button", style: .default, handler: { [unowned self] _ in
            self.isFirstButtonChecked = false
            print("Second Button tapped")
        })
        secondButton.setValue(!isFirstButtonChecked, forKey: "checked")

        let cancel = UIAlertAction(title: "Cancel", style: .cancel, handler: nil)

        let alert = UIAlertController(title: nil, message: nil, preferredStyle: .actionSheet)

        alert.addAction(firstButton)
        alert.addAction(secondButton)
        alert.addAction(cancel)
        self.present(alert, animated: true, completion: nil)
    }
}

You can also provide checkmark for bigger number of buttons using an enum:

class Controller: UIViewController {

    enum ButtonChecked {
        case first
        case second
        case third
        case forth
    }

    var buttonChecked: ButtonChecked = .first

    @IBAction func buttonTapped(_ sender: UIButton?) {
        let firstButton = UIAlertAction(title: "First Button", style: .default, handler: { [unowned self] _ in
            self.buttonChecked = .first
            print("First Button tapped")
        })

        let secondButton = UIAlertAction(title: "Second Button", style: .default, handler: { [unowned self] _ in
            self.buttonChecked = .second
            print("Second Button tapped")
        })

        let thirdButton = UIAlertAction(title: "Third Button", style: .default, handler: { [unowned self] _ in
            self.buttonChecked = .third
            print("Third Button tapped")
        })

        let forthButton = UIAlertAction(title: "Forth Button", style: .default, handler: { [unowned self] _ in
            self.buttonChecked = .forth
            print("Forth Button tapped")
        })

        let cancel = UIAlertAction(title: "Cancel", style: .cancel, handler: nil)

        switch buttonChecked {
        case .first:
            firstButton.setValue(true, forKey: "checked")
        case .second:
            secondButton.setValue(true, forKey: "checked")
        case .third:
            thirdButton.setValue(true, forKey: "checked")
        case .forth:
            forthButton.setValue(true, forKey: "checked")
        }

        let alert = UIAlertController(title: nil, message: nil, preferredStyle: .actionSheet)

        alert.addAction(firstButton)
        alert.addAction(secondButton)
        alert.addAction(thirdButton)
        alert.addAction(forthButton)
        alert.addAction(cancel)
        self.present(alert, animated: true, completion: nil)
    }
}

Solution 4

Another option is just to add a check mark character to a button title, like this "Title ✓". It will be next to the title, not at the right side of the button, but I think it's not a very big problem.

Share:
14,442

Related videos on Youtube

Jared Chu
Author by

Jared Chu

Just a developer who loves coding.

Updated on June 04, 2022

Comments

  • Jared Chu
    Jared Chu about 2 years

    I wonder how to add check mark to the right of actionSheet button the simplest way? Bellow is a screenshot of Podcasts app.

    enter image description here

    • rmaddy
      rmaddy over 7 years
      You need a custom alert since UIAlertController doesn't support such a feature.
    • rmaddy
      rmaddy over 7 years
      Apple has access to any API it wants. But there is no public API to do what you want with UIAlertController.
  • Jared Chu
    Jared Chu over 7 years
    I got my own answer, it's very simple :D
  • rmaddy
    rmaddy over 7 years
    Note that your solution can crash in a future update to iOS. You are accessing undocumented private APIs. Such solutions are very fragile.
  • rmaddy
    rmaddy over 7 years
    Please don't repost a previous answer (especially one you copied from someone else prior to that). Instead, vote to close as a duplicate.
  • Anbu.Karthik
    Anbu.Karthik over 7 years
    can you add the answer for modify the uialertaction text font,
  • Jared Chu
    Jared Chu over 7 years
    @Anbu.Karthik I will try it and update to github.com/jaredchu/JCActionSheet. Please note that solution can crash in a future update to iOS, so be careful if you use this solution for a production project.
  • Jared Chu
    Jared Chu over 7 years
    @Anbu.Karthik hi, it seems no way to change the font of UIAlertAction via hidden api, you can take a look here: github.com/nst/iOS-Runtime-Headers/blob/master/Frameworks/…
  • Anbu.Karthik
    Anbu.Karthik over 7 years
    @JaredChu - ya we can't change ,its comes in third layer,
  • Jared Chu
    Jared Chu almost 6 years
    Thanks, It's maybe the simplest way
  • Allison
    Allison over 5 years
    @JaredChu Those are synthesized getters and setters for a KVC property, still internal only
  • Jared Chu
    Jared Chu over 5 years
    You are right, but it's the easiest way. I added a notice because this post is getting more views.