Есть ли способ добавить UIPickerView в UIAlertController (Alert или ActionSheet) в Swift?
Я совершенно новичок в swift (и iOS-программировании вообще), но я начал возиться с ним (это была не очень хорошая идея, когда все еще бета-версия :D). Поэтому я попытался разобраться в этом сам, но все равно ничего. Даже попытался добавить subview, содержащий picker без успеха. Так кто-нибудь может мне помочь?
11 ответов
Ну это мой окончательный код, который работал для меня. Это смесь нескольких идей. Основные причины, по которым я приму мой ответ, - это то, что мой код в Swift, мой код использует UIAlertController, мой код для выбора. Я хочу поблагодарить Джагина - мой ответ основан на его идее.
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;
}
}
попробуйте это я сделал какой-то трюк...
ниже код работает для меня в iPod iOS8beta5 + XCode6
Я добавляю элемент управления UIActivityIndicatorView в UIAlertController в 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];
Примечание :
это в objective-c, но это доказывает, что мы также можем сделать это с помощью swift.
вы можете использовать аналогичный код в iOS8 / Swift, чтобы добавить свои собственные элементы управления в предупреждение (вместо листа действий), которое появляется в середине экрана.
единственная проблема, которую я имел с этим с alert.addSubView заключалось в том, что представление alert определяет размеры только в соответствии с элементами управления, добавленными с помощью методов класса. Затем вы должны добавить свои собственные ограничения, чтобы убедиться, что предупреждение охватывает все ваши элементы управления.
Я добавил пример здесь в качестве исходного вопроса задается Alert или 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)
}
Мне нужно было сделать то же самое, и вот как я это решил. Я сделала что-то похожее на Джагина. Мой код ниже. Обратите внимание, что я помещаю значения в UIPickerView в другую часть кода.
//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];
Я думаю, что неплохо начать с бета-версии.
Вам нужен custom UIAlertView
. Обратите внимание на UIAlertController
это доступно только в iOS 8.0.
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];
}
вы можете добавить Picker как UIActionSheet в iOS 8 с помощью Objective-C по: -
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;
}];
в ViewDidLoad добавьте это,
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)];
/ / это для создания ActionView и для выцветшего фона, когда выбор отображается во всплывающем окне.
-(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];
}];
}
// Отмена Нажмите Кнопку Способ.
-(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];
}];
}
/ / Для Кнопки Готово Нажмите.
здесь проект github это всплывает UIDatePicker в центре экрана. Он не использует UIAlertController или UIAlertView. Я не думаю, что это цель классов оповещения.
Swift 2.0:
сделайте образец pickerview или segment view и добавьте его в качестве подвида uialercontroller. Реализуйте делегаты uipickerview и представьте uialertcontroller. Вот как я достиг того же.
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()
}
}
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()
}
Swift 4.1 / Xcode 9.4.1 / 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: UIAlertControllerStyle.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: NSLayoutAttribute.height, relatedBy: NSLayoutRelation.greaterThanOrEqual, toItem: containerView, attribute: NSLayoutAttribute.height, multiplier: 1.00, constant: 130)
alert.view.addConstraint(cons)
let 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
present(alert, animated: true, completion: nil)
}