Добавьте UIDatePicker в UIAlertView

Я пытаюсь добавить средство выбора даты в представление предупреждений. Я могу добавить анимацию на экран по нажатию кнопки, и я вижу черный ящик, но не выбираю дату.

Вот что у меня пока есть....

- (IBAction)showDatePicker {
    CGRect frame = CGRectMake(200, self.view.frame.size.height, self.view.frame.size.width, 0);  //CGRectMake(225, 145, 260, 125);
    UIPickerView *datePicker = [[UIPickerView alloc] initWithFrame:frame];
    UIAlertView *showDateAlert = [[UIAlertView alloc]
                                  initWithTitle:@"Enter the Code Date"
                                  message:@"Sample message"
                                  delegate:self
                                  cancelButtonTitle:@"Cancel"
                                  otherButtonTitles:@"Update", nil];

    [self.view addSubview:datePicker];
    [UIView beginAnimations:@"slideIn" context:nil];
    [datePicker setCenter:CGPointMake(datePicker.frame.origin.x, self.view.frame.size.height - datePicker.frame.size.height/2)];
    [UIView commitAnimations];
}

Я нашел пример, который, кажется, работает, НО я не вижу никаких диалоговых окон или кнопок в моем окне предупреждения, только само средство выбора даты. Я что-то упустил здесь?

- (IBAction)showDatePicker {
    CGRect frame = CGRectMake(225, self.view.frame.size.height, self.view.frame.size.width, 125);
    UIDatePicker *datePicker = [[UIDatePicker alloc] initWithFrame:frame];
    datePicker = [[UIDatePicker alloc] init];
    datePicker.datePickerMode = UIDatePickerModeDate;

    [datePicker setDate:[NSDate date]];

    UIAlertView *alert;
    alert = [[UIAlertView alloc]
             initWithTitle:@"Enter the Code Date"
             message:@"Sample message"
             delegate:self
             cancelButtonTitle:@"Cancel"
             otherButtonTitles:@"Update", nil];
    alert.delegate = self;
    [alert addSubview:datePicker];
    [alert show];
}

person brianhevans    schedule 28.08.2012    source источник


Ответы (7)


Я согласен с комментаторами, которые говорят, что это не способ добиться этого по нескольким причинам. Во-первых, никому не нравится, когда постоянно появляются предупреждения. Во-вторых, и это не применимо к вашей ситуации, это может в конечном итоге привести к отклонению приложения. Apple изменила формулировку в ссылке на класс UIAlertView, ссылаясь на свою иерархию представлений как на частную; И мы все знаем, как Apple относится к тому, что вы балуетесь тем, что они считают личным.

Из ссылки на класс UIAlertView:

Класс UIAlertView предназначен для использования как есть и не поддерживает создание подклассов. Иерархия представлений для этого класса является закрытой и не может быть изменена.

Но так как вы говорите, что это частное приложение, вот и все. UIAlertView — это просто подкласс UIView. Таким образом, все правила рамок и границ остаются в силе. Вот базовый пример того, как настроить рамку средства выбора и границы предупреждения, чтобы втиснуть средство выбора даты.

// Create alert
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@"Hello" message:@"message" delegate:self cancelButtonTitle:@"Cancel" otherButtonTitles:@"OK", nil];
// Show alert (required for sizes to be available)
[alert show];
// Create date picker (could / should be an ivar)
UIDatePicker *picker = [[UIDatePicker alloc] initWithFrame:CGRectMake(10, alert.bounds.size.height, 320, 216)];
// Add picker to alert
[alert addSubview:picker];
// Adjust the alerts bounds
alert.bounds = CGRectMake(0, 0, 320 + 20, alert.bounds.size.height + 216 + 20);

ИЗМЕНИТЬ

Как было отмечено как в комментариях, так и в новых ответах на многие вопросы «как добавить представление к UIAlertView», этот метод больше не работает в iOS7 и выше. Это действительно следует воспринимать как доказательство того, что это в корне плохая идея.

Также обратите внимание на использование setValue:forKey: в широко распространенном «решении» «проблемы» невозможности изменить иерархию частных представлений Apple. setValue:forKey: — один из тех методов, который вызывает интерес у частных сканеров API. Найдите accessoryView в документации и заголовках UIAlertView. Это не в документах. Единственным связанным элементом в заголовках является ивар с именем _accessoryView, который помечен как @private.

Опять же, для внутреннего или частного приложения, я полагаю, это нормально, просто хорошо.

person NJones    schedule 28.08.2012
comment
Спасибо, NJones, это то, что я искал. Я понимаю, что все здесь говорят. Я приму это во внимание. - person brianhevans; 29.08.2012

В Swift:

        let myDatePicker: UIDatePicker = UIDatePicker()
        // setting properties of the datePicker
        myDatePicker.timeZone = NSTimeZone.localTimeZone()
        myDatePicker.frame = CGRectMake(0, 15, 270, 200)

        let alertController = UIAlertController(title: "\n\n\n\n\n\n\n\n", message: nil, preferredStyle: UIAlertControllerStyle.Alert)
        alertController.view.addSubview(myDatePicker)
        let somethingAction = UIAlertAction(title: "Ok", style: UIAlertActionStyle.Default, handler: nil)
        let cancelAction = UIAlertAction(title: "Cancel", style: UIAlertActionStyle.Cancel, handler: nil)
        alertController.addAction(somethingAction)
        alertController.addAction(cancelAction)
        self.presentViewController(alertController, animated: true, completion:{})
person Matheus Domingos    schedule 13.09.2016
comment
Работает отлично! - person Berat Baran Cevik; 12.06.2017

Вам не понравится этот ответ, но мой совет: не делайте этого! UIAlertView не предназначен для того, чтобы вы могли добавлять собственные подпредставления; примеры, которые вы найдете у людей, делающих это, являются примерами неправильного поведения. Создайте свое собственное представление, содержащее средство выбора, текст, кнопки и т. д., которые вы хотите, и представьте их как-нибудь. Например, вы можете представить его модально через собственный контроллер представления, например. с presentModalViewController:animated: или presentViewController:animated:completion:. Если вы используете iPad, вы можете использовать всплывающее окно (если это важно, оно может быть модальным).

person matt    schedule 28.08.2012
comment
У меня есть контроллер с разделенным представлением, и с правой стороны мне нужно разрешить пользователю выбирать дату. Есть несколько других элементов, которые пользователь должен будет заполнить. Мне действительно не нравится размер средства выбора даты, и я пытался найти лучший способ, но не видел никаких примеров. Можно ли переработать мой образец для достижения того же эффекта? - person brianhevans; 29.08.2012
comment
Эммм, почему? С точки зрения удобства использования, если все, что я хочу сделать, это позволить пользователю выбрать дату, это имеет смысл. Это частное приложение. Мне действительно не нужно, чтобы люди говорили мне, чего НЕ делать. Я хотел бы знать, КАК это сделать, пожалуйста. - person brianhevans; 29.08.2012

Это то, что сработало для меня (используя iOS7). Вызовите это перед [alertView show]:

[alertView setValue:customContentView forKey:@"accessoryView"];

Пример:

UIAlertView *av = [[UIAlertView alloc] initWithTitle:@"TEST" message:@"subview" delegate:nil cancelButtonTitle:@"NO" otherButtonTitles:@"YES", nil];
UIView *v = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 100, 50)];
v.backgroundColor = [UIColor yellowColor];
[av setValue:v forKey:@"accessoryView"];
[av show];

Источник: iOS 7 UIDatePicker в настройке UIAlertView

person Community    schedule 18.05.2014

Это работает для меня в ios7 и выше.

UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@"Select Date" message:@"" delegate:self cancelButtonTitle:@"Cancel" otherButtonTitles:@"OK", nil];
UIDatePicker *picker = [[UIDatePicker alloc] initWithFrame:CGRectMake(10, alert.bounds.size.height, 320, 216)];
[alert addSubview:picker];
alert.bounds = CGRectMake(0, 0, 320 + 20, alert.bounds.size.height + 216 + 20);
[alert setValue:picker forKey:@"accessoryView"];
[alert show];
person Akhilesh Mani    schedule 21.01.2015
comment
@Neela Добро пожаловать! - person Akhilesh Mani; 29.06.2017

Swift 5 версия ответа @Matheus Domingos

let myDatePicker: UIDatePicker = UIDatePicker()
myDatePicker.timeZone = NSTimeZone.local
myDatePicker.frame = CGRect(x: 0, y: 15, width: 270, height: 200)
let alertController = UIAlertController(title: "\n\n\n\n\n\n\n\n", message: nil, preferredStyle: UIAlertController.Style.alert)
alertController.view.addSubview(myDatePicker)
let somethingAction = UIAlertAction(title: "Ok", style: UIAlertAction.Style.default, handler: nil)
let cancelAction = UIAlertAction(title: "Cancel", style: UIAlertAction.Style.cancel, handler: nil)
alertController.addAction(somethingAction)
alertController.addAction(cancelAction)
present(alertController, animated: true, completion:{})

Свифт 5.2

let myDatePicker: UIDatePicker = UIDatePicker()
myDatePicker.timeZone = NSTimeZone.local
myDatePicker.frame = CGRect(x: 0, y: 15, width: 270, height: 200)
let alertController = UIAlertController(title: "\n\n\n\n\n\n\n\n", message: nil, preferredStyle: UIAlertController.Style.alert)
alertController.view.addSubview(myDatePicker)
let somethingAction = UIAlertAction(title: "Ok", style: UIAlertAction.Style.default, handler: nil)
let cancelAction = UIAlertAction(title: "Cancel", style: UIAlertAction.Style.cancel, handler: nil)
alertController.addAction(somethingAction)
alertController.addAction(cancelAction)
self.present(alertController, animated: true, completion: {})
person Ahmadreza    schedule 09.06.2019

Вот мое решение расширения UIViewController.

typealias DatePickerHandler = (_ success: Bool, _ date:Date) -> Void
typealias TimePickerHandler = (_ success: Bool, _ date:Date) -> Void
extension UIViewController{

func showDatePicker(completionHandler: @escaping DatePickerHandler){
    let vc = UIViewController()
    vc.preferredContentSize = CGSize(width: 250,height: 300)
    let pickerView = UIDatePicker(frame: CGRect(x: 0, y: 0, width: vc.view.bounds.width, height: 300))
    pickerView.datePickerMode = UIDatePicker.Mode.date
    if #available(iOS 13.4, *) {
        pickerView.preferredDatePickerStyle = .wheels
    } else {
        // Fallback on earlier versions
    }
     vc.view.addSubview(pickerView)
    NSLayoutConstraint.activate([
        pickerView.leadingAnchor.constraint(equalTo: vc.view.leadingAnchor,constant: 8),
        pickerView.trailingAnchor.constraint(equalTo: vc.view.trailingAnchor,constant: 8),
        pickerView.topAnchor.constraint(equalTo: vc.view.topAnchor,constant: 8),
        pickerView.bottomAnchor.constraint(equalTo: vc.view.bottomAnchor,constant: 8),
    ])

       let editRadiusAlert = UIAlertController(title: "Select Date", message: "", preferredStyle: UIAlertController.Style.actionSheet)
       editRadiusAlert.setValue(vc, forKey: "contentViewController")
       editRadiusAlert.addAction(UIAlertAction(title: "Select", style: .default, handler: {action in
        completionHandler(true,pickerView.date)
       }))
       editRadiusAlert.addAction(UIAlertAction(title: "Cancel", style: .cancel, handler: {action in
            completionHandler(false,Date())
       }))
       self.present(editRadiusAlert, animated: true)
}
func showTimePicker(completionHandler: @escaping TimePickerHandler){
    let vc = UIViewController()
    vc.preferredContentSize = CGSize(width: 250,height: 300)
    let pickerView = UIDatePicker(frame: CGRect(x: 0, y: 0, width: vc.view.bounds.width, height: 300))
    

    pickerView.datePickerMode = UIDatePicker.Mode.time
    if #available(iOS 13.4, *) {
        pickerView.preferredDatePickerStyle = .wheels
    } else {
        // Fallback on earlier versions
    }
    vc.view.addSubview(pickerView)
    NSLayoutConstraint.activate([
        pickerView.leadingAnchor.constraint(equalTo: vc.view.leadingAnchor,constant: 8),
        pickerView.trailingAnchor.constraint(equalTo: vc.view.trailingAnchor,constant: 8),
        pickerView.topAnchor.constraint(equalTo: vc.view.topAnchor,constant: 8),
        pickerView.bottomAnchor.constraint(equalTo: vc.view.bottomAnchor,constant: 8),
    ])
    

    let editRadiusAlert = UIAlertController(title: "Select Time", message: "", preferredStyle: UIAlertController.Style.actionSheet)
       editRadiusAlert.setValue(vc, forKey: "contentViewController")
       editRadiusAlert.addAction(UIAlertAction(title: "Select", style: .default, handler: {action in
            completionHandler(true,pickerView.date)
        }))
        editRadiusAlert.addAction(UIAlertAction(title: "Cancel", style: .cancel, handler: {action in
             completionHandler(false,Date())
        }))
    
    self.present(editRadiusAlert, animated: true)
}
}

Вот как использовать его в UIViewController

    showDatePicker { (isSuccess, date) in
        if(isSuccess){
        }
    }

Удачного кодирования!

person Muhammad Asyraf    schedule 02.05.2021