I am creating an registration dialog in swift with 3 text field and one Switch and I successfully add three text field two the Alert. The following code shows the same.
This answer is for Objective C. It doesn't use text fields but it does add a UISwitch to a UIAlertController as asked in the main question. I didn't find anything on SO that does exactly this so I'm posting this answer here, rather than posting another question that will get dinged as a duplicate.
This solution is used to enable users to sort a UITableView menu (of a list of projects...)
Thanks to the answer by @technerd, I also made the UISwitch change the text of a UILabel that is also on the same UIAlertController view. It uses KVC (Key-Value Coding) in the layer to pass the UILabel id to the target action when the UISwitch value is changed. (See the setOrderLabelText method in the code)
I was also trying to get around the trick of adding newlines ("\n\n\n\n") to the title or message to artificially move things around, by using constraints.
I used a horizontal UIStackView to hold the UISwitch and it's corresponding UILabel, and then used constraints to set the top anchor of the UIStack and a height constraint on the UIAlertController view to make it big enough to contain the UIStackView and the UIAlertController title.
I don't think it is possible to get the height of the title of the UIAlertController or the height of the action buttons. So I came up with values that worked well on an iPhone X and an iPad 2. As in other SO answers, I will likely come up with a home grown (or find one on GitHub) solution to make this more robust. But since I got this far and got so much from other awesome SO answers, I wanted to give back a bit and share my results.
Here's a screenshot:
And here's the code:
// using KVC, set the label text based on the label tag and toggle the tag
- (void)setOrderLabelText:(UISwitch *)orderSwitch {
UILabel *label = (UILabel *)[orderSwitch.layer valueForKey:@"label"];
label.text = label.tag ? @"Ascending" : @"Descending";
label.tag = label.tag ? 0 : 1;
}
// sort the data based on the user's selections
- (IBAction)sort:(UIButton *)sortButton {
UILabel *label = [[UILabel alloc] init];
label.text = @"Ascending";
label.textColor = UIColor.grayColor;
label.tag = 0;
[label sizeToFit];
UISwitch *orderSwitch = [[UISwitch alloc] init];
orderSwitch.on = YES;
[orderSwitch setOn:YES animated:YES];
// allow the switch to change the text in the label using KVC (key-value coding)
[orderSwitch addTarget:self action:@selector(setOrderLabelText:) forControlEvents:UIControlEventValueChanged];
[orderSwitch.layer setValue:label forKey:@"label"];
UIStackView *stackView = [[UIStackView alloc] init];
stackView.axis = UILayoutConstraintAxisHorizontal;
stackView.spacing = 8;
[stackView addArrangedSubview:orderSwitch];
[stackView addArrangedSubview:label];
UIAlertController *alert = [UIAlertController
alertControllerWithTitle: @"Sort Projects By"
message: nil
preferredStyle:UIAlertControllerStyleAlert];
UIAlertAction *createdButton = [UIAlertAction
actionWithTitle:@"Created"
style:UIAlertActionStyleDestructive
handler:^(UIAlertAction * action) {
[self sortBy:@"created" ascending:orderSwitch.isOn];
}];
UIAlertAction *titleButton = [UIAlertAction
actionWithTitle:@"Title"
style:UIAlertActionStyleDestructive
handler:^(UIAlertAction * action) {
[self sortBy:@"title" ascending:orderSwitch.isOn];
}];
UIAlertAction *subtitleButton = [UIAlertAction
actionWithTitle:@"Subtitle"
style:UIAlertActionStyleDestructive
handler:^(UIAlertAction * action) {
[self sortBy:@"subtitle" ascending:orderSwitch.isOn];
}];
UIAlertAction *cancelButton = [UIAlertAction
actionWithTitle:@"Cancel"
style:UIAlertActionStyleCancel
handler:^(UIAlertAction * action) {
}];
// add action buttons to the alert
[alert addAction:createdButton];
[alert addAction:titleButton];
[alert addAction:subtitleButton];
[alert addAction:cancelButton];
[alert.view addSubview:stackView];
// center the stack in the alert
[stackView.centerXAnchor constraintEqualToAnchor:alert.view.centerXAnchor].active = YES;
// turn off the autoresizing mask or things get weird
stackView.translatesAutoresizingMaskIntoConstraints = NO;
// use a topAnchor constraint to place the stackview, just below the title
// TODO: figure out how to get the height of the alert title (use 64 for now)
[stackView.topAnchor constraintEqualToAnchor:alert.view.topAnchor constant:64].active = YES;
// layout now to set the view bounds so far - NOTE this does not include the action buttons
[alert.view layoutIfNeeded];
// use a height constraint to make the alert view big enough to hold my stack view
// NOTE: strange, but this must include the header view AND all the action buttons
// TODO: figure out how to get the height of the action buttons (use 52 for each action button for now)
CGFloat height = alert.view.bounds.size.height + alert.actions.count * 52 + stackView.bounds.size.height;
[alert.view.heightAnchor constraintEqualToConstant:height].active = YES;
[self presentViewController:alert animated:YES completion:nil];
}