31

I'm totally new to swift (and iOS programming at all), but I started messing around with it (it wasn't a good idea when everything is still beta version :D). So I tried to figure it out by myself, but still nothing. Even tried to add subview containing picker without any success. So can any one help me?

Hristo Atanasov
  • 1,236
  • 2
  • 18
  • 25
  • I had successfully add spinner control in UIAlertController, you can also add UIPickerView with same logic here is a link http://stackoverflow.com/questions/25652101/please-wait-dialog-in-ios8/25671652#25671652 – Jageen Sep 05 '14 at 04:10
  • 1
    That is cool ... I saw it ... But I cant vote for your answer (no reputation) – Hristo Atanasov Sep 05 '14 at 09:25
  • 1
    posting answer here but it's in objective-c – Jageen Sep 05 '14 at 09:32
  • 2
    Apple docs say not to subclass UIAlertController due to trickiness with its internal view hierarchy. So I think the below answers are dangerous. (And I could not get them to work for me.) See this other question who's accepted answer states this: http://stackoverflow.com/questions/24330152/showing-a-uipickerview-with-uiactionsheet-in-ios8-not-working – webjprgm Dec 05 '15 at 21:10
  • I don't see anything dangerous in the answers below. I hope iPhone would not explode because of a modified Action sheet. And why should I create some element if there is existing one which I can use. Apple says for lots of things that they are not invented for the purpose developers need, but they don't invent anything useful for them needs. So the all Swift is one challenge to deal with. I can't imagine one serious application project without using some sort of hacks or tricks if you want to make it as you wish. This all examples works fine. Everyone can use it on free will .. :) – Hristo Atanasov Dec 07 '15 at 09:43
  • 1
    Apple's documentation of UIAlertController **explicitly** warn you NOT to touch the view hierarchy, which all of these answers are doing with `alertcontroller.view.addSubview` . Don't do this, or you'll end up regretting it later – xaphod Oct 07 '16 at 20:54

12 Answers12

30

Well this is my final code which worked for me. It is a mix by a few ideas. The main reasons that I will accept my answer is that my code is in Swift, my code uses UIAlertController, my code is for picker. I want to thank to Jageen - my answer is based on his idea.

    func showPickerInActionSheet(sentBy: String) {
    var title = ""
    var message = "\n\n\n\n\n\n\n\n\n\n";
    var alert = UIAlertController(title: title, message: message, preferredStyle: UIAlertControllerStyle.ActionSheet);
    alert.modalInPopover = true;


    //Create a frame (placeholder/wrapper) for the picker and then create the picker
    var pickerFrame: CGRect = CGRectMake(17, 52, 270, 100); // CGRectMake(left), top, width, height) - left and top are like margins
    var picker: UIPickerView = UIPickerView(frame: pickerFrame);

    /* If there will be 2 or 3 pickers on this view, I am going to use the tag as a way
    to identify them in the delegate and datasource. /* This part with the tags is not required.
    I am doing it this way, because I have a variable, witch knows where the Alert has been invoked from.*/
    if(sentBy == "profile"){
        picker.tag = 1;
    } else if (sentBy == "user"){
        picker.tag = 2;
    } else {
        picker.tag = 0;
    }

    //set the pickers datasource and delegate
    picker.delegate = self;
    picker.dataSource = self;

    //Add the picker to the alert controller
    alert.view.addSubview(picker);

    //Create the toolbar view - the view witch will hold our 2 buttons 
    var toolFrame = CGRectMake(17, 5, 270, 45);
    var toolView: UIView = UIView(frame: toolFrame);

    //add buttons to the view
    var buttonCancelFrame: CGRect = CGRectMake(0, 7, 100, 30); //size & position of the button as placed on the toolView

    //Create the cancel button & set its title
    var buttonCancel: UIButton = UIButton(frame: buttonCancelFrame);
    buttonCancel.setTitle("Cancel", forState: UIControlState.Normal);
    buttonCancel.setTitleColor(UIColor.blueColor(), forState: UIControlState.Normal);
    toolView.addSubview(buttonCancel); //add it to the toolView

    //Add the target - target, function to call, the event witch will trigger the function call
    buttonCancel.addTarget(self, action: "cancelSelection:", forControlEvents: UIControlEvents.TouchDown);


    //add buttons to the view
    var buttonOkFrame: CGRect = CGRectMake(170, 7, 100, 30); //size & position of the button as placed on the toolView

    //Create the Select button & set the title
    var buttonOk: UIButton = UIButton(frame: buttonOkFrame);
    buttonOk.setTitle("Select", forState: UIControlState.Normal);
    buttonOk.setTitleColor(UIColor.blueColor(), forState: UIControlState.Normal);
    toolView.addSubview(buttonOk); //add to the subview

    //Add the tartget. In my case I dynamicly set the target of the select button
    if(sentBy == "profile"){
        buttonOk.addTarget(self, action: "saveProfile:", forControlEvents: UIControlEvents.TouchDown);
    } else if (sentBy == "user"){
        buttonOk.addTarget(self, action: "saveUser:", forControlEvents: UIControlEvents.TouchDown);
    }

    //add the toolbar to the alert controller
    alert.view.addSubview(toolView);

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

func saveProfile(sender: UIButton){
    // Your code when select button is tapped

}

func saveUser(sender: UIButton){
    // Your code when select button is tapped
}

func cancelSelection(sender: UIButton){
    println("Cancel");
    self.dismissViewControllerAnimated(true, completion: nil);
    // We dismiss the alert. Here you can add your additional code to execute when cancel is pressed
}

// returns number of rows in each component..
func pickerView(pickerView: UIPickerView, numberOfRowsInComponent component: Int) -> Int{
    if(pickerView.tag == 1){
        return self.profilesList.count;
    } else if(pickerView.tag == 2){
        return self.usersList.count;
    } else  {
        return 0;
    }
}

// Return the title of each row in your picker ... In my case that will be the profile name or the username string
func pickerView(pickerView: UIPickerView, titleForRow row: Int, forComponent component: Int) -> String! {
    if(pickerView.tag == 1){

            var selectedProfile: Profiles = self.profilesList[row] as Profiles;
            return selectedProfile.profileName;

    } else if(pickerView.tag == 2){

            var selectedUser: Users = self.usersList[row] as Users;
            return selectedUser.username;

    } else  {

        return "";

    }

}

func pickerView(pickerView: UIPickerView, didSelectRow row: Int, inComponent component: Int) {
    if(pickerView.tag == 1){
            var choosenProfile: Profiles = profilesList[row] as Profiles;
            self.selectedProfile = choosenProfile.profileName;
    } else if (pickerView.tag == 2){
            var choosenUser: Profiles = usersList[row] as Users;
            self.selectedUsername = choosenUser.username;
    }

}
Hristo Atanasov
  • 1,236
  • 2
  • 18
  • 25
9

Try this I done some trick...

Below code is working for me in iPod iOS8beta5 + XCode6
I add UIActivityIndicatorView control in UIAlertController in objective-c.

UIAlertController *alert = [UIAlertController alertControllerWithTitle:nil
                                        message:@"Please wait\n\n\n"
                                 preferredStyle:UIAlertControllerStyleAlert];

    UIActivityIndicatorView *spinner = [[UIActivityIndicatorView alloc] initWithActivityIndicatorStyle:UIActivityIndicatorViewStyleWhiteLarge];
    spinner.center = CGPointMake(130.5, 65.5);
    spinner.color = [UIColor blackColor];
    [spinner startAnimating];
    [alert.view addSubview:spinner];
    [self presentViewController:alert animated:NO completion:nil];

enter image description here


Note :
It's in objective-c but by this it's prove that we can also do this using swift.
Jageen
  • 6,345
  • 2
  • 37
  • 56
8

You can use similar code in In iOS8 / Swift to add your own controls into an alert (instead of an action sheet) that pops up in the middle of the screen.

The only problem I had with doing this with alert.addSubView was that the alert view only sizes itself according to the controls you have added through the class methods. You have to then add your own constraints to make sure that the alert encompasses all your controls.

I've added an example here as the original question asked for Alert or ActionSheet

func addAlert(){

    // create the alert
    let title = "This is the title"
    let message = "This is the message"
    var alert = UIAlertController(title: title, message: message, preferredStyle: UIAlertControllerStyle.Alert);
    alert.modalInPopover = true;

    // add an action button
    let nextAction: UIAlertAction = UIAlertAction(title: "Action", style: .Default){action->Void in
        // do something
    }
    alert.addAction(nextAction)

    // now create our custom view - we are using a container view which can contain other views
    let containerViewWidth = 250
    let containerViewHeight = 120
    var containerFrame = CGRectMake(10, 70, CGFloat(containerViewWidth), CGFloat(containerViewHeight));
    var containerView: UIView = UIView(frame: containerFrame);

    alert.view.addSubview(containerView)

    // now add some constraints to make sure that the alert resizes itself
    var cons:NSLayoutConstraint = NSLayoutConstraint(item: alert.view, attribute: NSLayoutAttribute.Height, relatedBy: NSLayoutRelation.GreaterThanOrEqual, toItem: containerView, attribute: NSLayoutAttribute.Height, multiplier: 1.00, constant: 130)

    alert.view.addConstraint(cons)

    var cons2:NSLayoutConstraint = NSLayoutConstraint(item: alert.view, attribute: NSLayoutAttribute.Width, relatedBy: NSLayoutRelation.GreaterThanOrEqual, toItem: containerView, attribute: NSLayoutAttribute.Width, multiplier: 1.00, constant: 20)

    alert.view.addConstraint(cons2)

    // present with our view controller
    presentViewController(alert, animated: true, completion: nil)

}
leafcutter
  • 747
  • 7
  • 14
5

Swift 5.2 / Xcode 11.6 / iOS 11.4

func addAlert(){

    // create the alert
    let title = "This is the title"
    let message = "This is the message"
    let alert = UIAlertController(title: title, message: message, preferredStyle: UIAlertController.Style.alert);
    alert.isModalInPopover = true;

    // add an action button
    let nextAction: UIAlertAction = UIAlertAction(title: "Action", style: .default){action->Void in
        // do something
    }
    alert.addAction(nextAction)

    // now create our custom view - we are using a container view which can contain other views
    let containerViewWidth = 250
    let containerViewHeight = 120
    let containerFrame = CGRect(x:10, y: 70, width: CGFloat(containerViewWidth), height: CGFloat(containerViewHeight));
    let containerView: UIView = UIView(frame: containerFrame);

    alert.view.addSubview(containerView)

    // now add some constraints to make sure that the alert resizes itself
    let cons:NSLayoutConstraint = NSLayoutConstraint(item: alert.view, attribute: NSLayoutConstraint.Attribute.height, relatedBy: NSLayoutConstraint.Relation.greaterThanOrEqual, toItem: containerView, attribute: NSLayoutConstraint.Attribute.height, multiplier: 1.00, constant: 130)

    alert.view.addConstraint(cons)

    let cons2:NSLayoutConstraint = NSLayoutConstraint(item: alert.view, attribute: NSLayoutConstraint.Attribute.width, relatedBy: NSLayoutConstraint.Relation.greaterThanOrEqual, toItem: containerView, attribute: NSLayoutConstraint.Attribute.width, multiplier: 1.00, constant: 20)

    alert.view.addConstraint(cons2)

    // present with our view controller
    present(alert, animated: true, completion: nil)

}
Declan McKenna
  • 4,321
  • 6
  • 54
  • 72
drewster
  • 5,460
  • 5
  • 40
  • 50
4

I needed to do the same thing and this is how I resolved it. I did something similar to Jageen. My code is below. Note that I put values in the UIPickerView in a different part of the code.

//Need to use an UIAlertController for iOS 8 instead of an action view
UIAlertController *alert = [UIAlertController alertControllerWithTitle:nil
                              message:@"\n\n\n\n\n\n\n\n"
                              preferredStyle:UIAlertControllerStyleAlert];

//Make a frame for the picker & then create the picker
CGRect pickerFrame = CGRectMake(0, 0, 270, 100);
UIPickerView *regionsPicker = [[UIPickerView alloc] initWithFrame:pickerFrame];

//There will be 3 pickers on this view so I am going to use the tag as a way
//to identify them in the delegate and datasource
regionsPicker.tag = 1;

//set the pickers datasource and delegate
regionsPicker.dataSource = self;
regionsPicker.delegate = self;

//set the pickers selection indicator to true so that the user will now which one that they are chosing
[regionsPicker setShowsSelectionIndicator:YES];

//Add the picker to the alert controller
[alert.view addSubview:regionsPicker];

//make the toolbar view
UIView *toolView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 270.0f, 44.f)];
toolView.backgroundColor = [UIColor blackColor]; //set it's background


//add buttons to the view
CGRect buttonFrame = CGRectMake(0, 5, 100, 30); //size & position of the button as placed on the toolView
//make the cancel button & set the title
UIButton *button = [[UIButton alloc] initWithFrame: buttonFrame];
[button setTitle: @"Cancel" forState: UIControlStateNormal];
[button setTitleColor: [UIColor blueColor] forState: UIControlStateNormal]; //make the color blue to keep the same look as prev version
[toolView addSubview:button]; //add to the subview

//Add the tartget
[button addTarget: self
           action: @selector(cancelRegionSet)
 forControlEvents: UIControlEventTouchDown];

//do the same for the select button
buttonFrame = CGRectMake(90, 5, 100, 30);
UIButton *selButton = [[UIButton alloc] initWithFrame:buttonFrame];
[selButton setTitle:@"Select" forState:UIControlStateNormal];
[selButton setTitleColor:[UIColor blueColor] forState:UIControlStateNormal];
[toolView addSubview:selButton];

[selButton addTarget: self
              action: @selector(dismissRegionSet:)
 forControlEvents: UIControlEventTouchDown];

//add the toolbar to the alert controller
[alert.view addSubview:toolView];

[self presentViewController:alert animated:NO completion:nil];
inosu812
  • 101
  • 2
  • 9
4

You can add Picker like UIActionSheet in iOS 8 using Objective-C by:-

 colorArray = [[NSMutableArray alloc ]initWithObjects:@"One", @"Two", @"Three", @"Four", @"Five", nil];
picker = [[UIPickerView alloc]init];
picker.frame = CGRectMake(0.0, 44.0,self.view.frame.size.width, 216.0);
picker.dataSource = self;
picker.delegate = self;
picker.showsSelectionIndicator = true;
picker.backgroundColor = [UIColor whiteColor];

UIToolbar* pickerDateToolbar = [[UIToolbar alloc] initWithFrame: CGRectMake(0, 0, 320, 44)];  //(frame: CGRectMake(0, 0, 320, 44))
pickerDateToolbar.barStyle =  UIBarStyleBlackTranslucent;//UIBarStyle.Black
pickerDateToolbar.barTintColor = [UIColor whiteColor];
pickerDateToolbar.translucent = true;
actionView.backgroundColor = [UIColor whiteColor];


UILabel* label = [[UILabel alloc] initWithFrame:CGRectMake(150, 5, 150, 20)];
label.backgroundColor = [UIColor clearColor];
label.textColor = [UIColor blackColor];
label.shadowColor = [UIColor blackColor];
label.shadowOffset = CGSizeMake(0, 1);
label.font = [UIFont systemFontOfSize:15];//[UIFont boldSystemFontOfSize:15];
label.text = @"Select a Status";
UIBarButtonItem *labeltext= [[UIBarButtonItem alloc] initWithCustomView:label];


UIBarButtonItem *cancelBtn = [[UIBarButtonItem alloc] initWithTitle:@"Cancel" style:UIBarButtonItemStylePlain target:self action:@selector(cancel_clicked:)];

UIBarButtonItem *flexSpace = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemFlexibleSpace target:nil action:nil];

UIBarButtonItem *doneBtn = [[UIBarButtonItem alloc] initWithTitle:@"Done" style:UIBarButtonItemStylePlain target:self action:@selector(done_clicked:)];

pickerDateToolbar.items = [[NSArray alloc] initWithObjects:cancelBtn,flexSpace,labeltext,doneBtn,nil];

cancelBtn.tintColor = [UIColor blueColor];
doneBtn.tintColor = [UIColor blueColor];

[actionView addSubview:pickerDateToolbar];
[actionView addSubview:picker];

if (window != nil) {
[window addSubview:actionView];
}
else
{
[self.view addSubview:actionView];
}

[UIView animateWithDuration:(0.2) animations:^{
actionView.frame = CGRectMake(0, self.view.frame.size.height - 260.0, self.view.frame.size.width, 260.0);
self.view.alpha = 0.5;
actionView.alpha = 1;
}];

In ViewDidLoad add this,

UIApplication * delegate = [UIApplication sharedApplication];
UIWindow *myWindow = delegate.keyWindow;
NSArray *myWindow2 = delegate.windows;

if(myWindow == [UIApplication sharedApplication].keyWindow)
window = myWindow;
else
window = myWindow2[0];

actionView = [[UIView alloc]initWithFrame:CGRectMake(0, UIScreen.mainScreen.bounds.size.height, UIScreen.mainScreen.bounds.size.width, 240.0)];

// This is to Create ActionView and for faded background when picker is displayed in popup.

-(void)cancel_clicked:(id)sender{
NSLog(@"cancel clicked");
[UIView animateWithDuration:0.2 animations:^{
actionView.frame = CGRectMake(0, UIScreen.mainScreen.bounds.size.height - 260.0, UIScreen.mainScreen.bounds.size.width, 260.0);
} completion:^(BOOL finished) {
self.view.alpha = 1;
[actionView removeFromSuperview];
}];

}

// Cancel Button Click Method.

-(void)done_clicked:(id)sender{
NSLog(@"done clicked");
self.view.userInteractionEnabled = TRUE;

[UIView animateWithDuration:0.2 animations:^{
actionView.frame = CGRectMake(0, UIScreen.mainScreen.bounds.size.height - 260.0, UIScreen.mainScreen.bounds.size.width, 260.0);
} completion:^(BOOL finished) {
_permitStatus.text = [colorArray objectAtIndex:[picker selectedRowInComponent:0]];
self.view.alpha = 1;
[actionView removeFromSuperview];
}];

}

// For Done Button Click.

Programming Learner
  • 4,351
  • 3
  • 22
  • 34
3

I think it is not bad idea to start from beta. You need custom UIAlertView. Pay attention to UIAlertController it's available only in iOS 8.0.

Look there and there

Max
  • 1,341
  • 3
  • 20
  • 39
  • Can you give me a litle example in swift, because i didn't get the examples in you links (I think it's because too much ObjC in there ;) ) – Hristo Atanasov Aug 28 '14 at 12:25
  • I think you should start from another point of Swift where you'll get the knowledge how it's work. You **should** know how to convert code from obj-c to swift because obj-c was "main" language a lot of time of iOS as you know and there available some info, frameworks, examples of obj-c that could help you. – Max Aug 28 '14 at 12:48
  • I think that this is the big problem of apple. They are trying to make very slow transition between objective c and swift, making xcode to work with both, to ease the obc-c programmers. But what about people starting now ... they have to learn 2 programming languages, because swift cannot work alone without obj-c (most of the frameworks are in obj-c). Swift is not a language even, it is a closure for the old and old and old C and obj-c ... or apple just make me feel it like that ... Take for example Java, C#, PHP, even javascript ... they can all survive without use of any other language so .. – Hristo Atanasov Aug 28 '14 at 13:20
  • Thanks for the advice to start learning Swift from another point ... But this is advice for apple - to start creating swift from another point. A point where swift can work stand alone. So Maxim ... I liked your first comment. It's a hint for starting from somewhere ... I'm starting in this direction, but I'll wait for bether explanation ... Don't get angry ... I do not even have reputation to choose the best answer or vote for it so ... Stay cool ... ;) – Hristo Atanasov Aug 28 '14 at 13:26
  • Coool .. Probably it is the same like with Bulgarian and Russian languages. You're writing in Russian, but I can still understand what you've meant :) – Hristo Atanasov Aug 28 '14 at 13:30
  • Sorry. You have Russian language nickname :) – Max Aug 28 '14 at 13:31
  • It is Bulgarian ... And I understood what you've wrote me. – Hristo Atanasov Aug 28 '14 at 13:33
2

Here is a github project that pops up a UIDatePicker in the center of the screen. It does not use UIAlertController or UIAlertView. I don't think that's the intent of the alert classes.

Gene De Lisa
  • 3,628
  • 1
  • 21
  • 36
2
alertController = [UIAlertController alertControllerWithTitle:@" \n\n\n\n\n\n\n\n\n\n"
                                                      message:@""
                                               preferredStyle:UIAlertControllerStyleActionSheet];

closePicker = [[UISegmentedControl alloc] initWithItems:[NSArray arrayWithObject:@"Cancel"]];
closePicker.momentary = YES;
closePicker.frame = CGRectMake(25, 0.0f, 50.0f, 30.0f);
closePicker.segmentedControlStyle = UISegmentedControlStyleBar;
closePicker.tintColor = [UIColor blackColor];
[closePicker addTarget:self action:@selector(dismissActionSheet:) forControlEvents:UIControlEventValueChanged];
[alertController.view addSubview:closePicker];


UIPickerView *pickerFiliter=[[UIPickerView alloc]init];
pickerFiliter = [[UIPickerView alloc] initWithFrame:CGRectMake(0.0, 40.0, 320.0, 120.0)];
pickerFiliter.showsSelectionIndicator = YES;
pickerFiliter.dataSource = self;
pickerFiliter.delegate = self;

[alertController.view addSubview:pickerFiliter];


[self presentViewController:alertController animated:YES completion:nil];


- (IBAction)dismissActionSheet:(id)sender 
 {

    [alertController dismissViewControllerAnimated:YES completion:nil];

 }
Yucel Bayram
  • 1,653
  • 2
  • 22
  • 41
1

Swift 2.0:

Make a sample pickerview or segment view and add it as uialercontroller's subview. Implement uipickerview delegates and present the uialertcontroller. Here is how I achieved the same.

class ViewController: 

    UIViewController,UIPickerViewDataSource,UIPickerViewDelegate {

     var samplePicker: UIPickerView = UIPickerView()
     var sampleSegment:UISegmentedControl = UISegmentedControl ()
     var alertController:UIAlertController = UIAlertController()
     var buildings:[String] = ["BankBuilding", "Cinema" , "CornerShop", "Greg's House","14th Street"]

     override func viewDidLoad() {
      super.viewDidLoad()

      samplePicker = UIPickerView(frame: CGRectMake(10.0, 40.0, 250, 150))
      samplePicker.delegate =  self;
      samplePicker.dataSource = self;
      samplePicker.showsSelectionIndicator = true
      samplePicker.tintColor =  UIColor.redColor()
      samplePicker.reloadAllComponents()


      sampleSegment = UISegmentedControl(items: NSArray(object: "  Dismiss ") as [AnyObject])
      sampleSegment.momentary = true
      sampleSegment.frame = CGRectMake(25, 10.0, 100.0, 30.0)
      sampleSegment.tintColor = UIColor.blackColor()
      sampleSegment.backgroundColor = UIColor.orangeColor()
      sampleSegment.addTarget(self, action: "dismissAlert", forControlEvents: UIControlEvents.ValueChanged)

     }
     func numberOfComponentsInPickerView(pickerView: UIPickerView) -> Int {

      return 1
     }

     func pickerView(pickerView: UIPickerView, numberOfRowsInComponent component: Int) -> Int {
      return 3
     }

     func pickerView(pickerView: UIPickerView, titleForRow row: Int, forComponent component: Int) -> String? {

      return buildings[row] as String
     }

     func pickerView(pickerView: UIPickerView, didSelectRow row: Int, inComponent component: Int) {
      print(buildings[0])

     }
     func pickerView(pickerView: UIPickerView, rowHeightForComponent component: Int) -> CGFloat {
      return 36.0
     }
     override func viewDidAppear(animated: Bool)
     {
      alertController = UIAlertController(title: " \n\n\n\n\n\n\n\n\n\n", message: "", preferredStyle: UIAlertControllerStyle.Alert)

      alertController.view.addSubview(sampleSegment)
      alertController.view.addSubview(samplePicker)

      self.presentViewController(alertController, animated: true, completion: nil)

     }
     func dismissAlert()
     {
      alertController.dismissViewControllerAnimated(true, completion: nil)
     }
     override func didReceiveMemoryWarning() {
      super.didReceiveMemoryWarning()

     }
    }
Alvin George
  • 14,148
  • 92
  • 64
1

Swift 3.0:

func showPickerInActionSheet() {

    let title = ""
    let message = "\n\n\n\n\n\n\n\n\n\n";
    let alert = UIAlertController(title: title, message: message, preferredStyle: UIAlertControllerStyle.actionSheet);
    alert.isModalInPopover = true;


    //Create a frame (placeholder/wrapper) for the picker and then create the picker
    let pickerFrame = CGRect(x: 17, y: 52, width: 270, height: 100)
    let picker: UIPickerView = UIPickerView(frame: pickerFrame)


    //set the pickers datasource and delegate
    picker.delegate   = self
    picker.dataSource = self

    //Add the picker to the alert controller
    alert.view.addSubview(picker)

    //Create the toolbar view - the view witch will hold our 2 buttons
    let toolFrame = CGRect(x: 17, y: 5, width: 270, height: 45)
    let toolView: UIView = UIView(frame: toolFrame)


    //add buttons to the view
    let buttonCancelFrame = CGRect(x: 0, y: 7, width: 100, height: 30) //size & position of the button as placed on the toolView

    //Create the cancel button & set its title
    let buttonCancel: UIButton = UIButton(frame: buttonCancelFrame);
    buttonCancel.setTitle("Cancel", for: .normal)
    buttonCancel.setTitleColor(UIColor.blue, for: .normal)
    toolView.addSubview(buttonCancel); //add it to the toolView

    //Add the target - target, function to call, the event witch will trigger the function call
    buttonCancel.addTarget(self, action: Selector("cancelSelection:"), for: UIControlEvents.touchDown);


    //add buttons to the view

    let buttonOkFrame = CGRect(x: 170, y: 7, width: 100, height: 30)//size & position of the button as placed on the toolView

    //Create the Select button & set the title
    let buttonOk: UIButton = UIButton(frame: buttonOkFrame);
    buttonOk.setTitle("Select", for: UIControlState.normal);
    buttonOk.setTitleColor(UIColor.blue, for: UIControlState.normal);
    toolView.addSubview(buttonOk); //add to the subview

    buttonOk.addTarget(self, action: #selector(HomeViewController.saveDelayTime), for: UIControlEvents.touchDown);

    //add the toolbar to the alert controller
    alert.view.addSubview(toolView);

    self.present(alert, animated: true, completion: nil);
}

func saveProfile(sender: UIButton){
    // Your code when select button is tapped

}

func saveUser(sender: UIButton){
    // Your code when select button is tapped
}

func cancelSelection(sender: UIButton){
    self.dismiss(animated: true, completion: nil)

    // We dismiss the alert. Here you can add your additional code to execute when cancel is pressed
}

// returns number of rows in each component..
func numberOfComponents(in pickerView: UIPickerView) -> Int{
    return 1
}

func pickerView(_ pickerView: UIPickerView, numberOfRowsInComponent component: Int) -> Int {
    return 60
}

// Return the title of each row in your picker ... In my case that will be the profile name or the username string
func pickerView(_ pickerView: UIPickerView, titleForRow row: Int, forComponent component: Int) -> String? {
    return "\(row)"

}

func pickerView(_ pickerView: UIPickerView, didSelectRow row: Int, inComponent component: Int) {
    selectedTime = row
}

func saveDelayTime() {
    self.dismiss(animated: true, completion: nil)
    UserDefaults.standard.set(selectedTime, forKey: "DelayTimeKey")
    let _ = UserDefaults.standard.synchronize()
}
random
  • 8,568
  • 12
  • 50
  • 85
1

This is an alert with a picker with a static array for picker values.

    func presentAlertWithPicker(title: String,
                             message: String,
                             pickerOptions: [String],
                             completion: @escaping ((_ pickerValueString: String) -> Void)){
        
        // Add a picker handler to provide the picker in the alert with the needed data
        class PickerHandler: NSObject, UIPickerViewDelegate, UIPickerViewDataSource{
            var items: [String]
            lazy var lastSelectedItem = items[0]
            
            init(items: [String]){
                self.items = items
                super.init()
            }

            func numberOfComponents(in pickerView: UIPickerView) -> Int {
                1
            }
            
            func pickerView(_ pickerView: UIPickerView, numberOfRowsInComponent component: Int) -> Int {
                items.count
            }
            
            func pickerView(_ pickerView: UIPickerView, titleForRow row: Int, forComponent component: Int) -> String? {
                items[row]
            }
            
            func pickerView(_ pickerView: UIPickerView, didSelectRow row: Int, inComponent component: Int) {
                print("selected item tag is \(pickerView.tag), row: \(row)")
                lastSelectedItem = items[row]
            }
        }
        
        DispatchQueue.main.async { [weak self] in
            let pickerHandler = PickerHandler(items: pickerOptions)
            let pickerView = UIPickerView(frame: .zero)
            pickerView.delegate = pickerHandler
            pickerView.dataSource = pickerHandler

            let title = title
            let message = message
            let alert = UIAlertController(title: title, message: message, preferredStyle: .alert);
            
            let selectAction = UIAlertAction(title: "Select", style: .default){action->Void in
                completion(pickerHandler.lastSelectedItem)
            }
            alert.addAction(selectAction)
            
            // Add the picker view
            alert.view.addSubview(pickerView)
            pickerView.translatesAutoresizingMaskIntoConstraints = false
            let constantAbovePicker: CGFloat = 70
            let constantBelowPicker: CGFloat = 50
            NSLayoutConstraint.activate([
                pickerView.leadingAnchor.constraint(equalTo: alert.view.leadingAnchor, constant:  10),
                pickerView.widthAnchor.constraint(equalToConstant: 250),
                pickerView.widthAnchor.constraint(lessThanOrEqualTo: alert.view.widthAnchor, constant: 20),

                pickerView.topAnchor.constraint(equalTo: alert.view.topAnchor, constant:  constantAbovePicker),
                pickerView.heightAnchor.constraint(equalToConstant: 150),
                alert.view.bottomAnchor.constraint(greaterThanOrEqualTo: pickerView.bottomAnchor, constant:  constantBelowPicker),
            ])

            self?.present(alert, animated: true, completion: nil)
        }
    }

To call it.

            presentAlertWithPicker(title: "This is the main title",
                                        message: "This is the main message",
                                        pickerOptions: ["1", "2", "3"]) { (pickerSelectedValue) in
                
                print(pickerSelectedValue)
            }
M. Adam
  • 108
  • 5