UIDatePicker с панелью инструментов, но без текстового поля

#ios #swift #uidatepicker

Вопрос:

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

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

Ниже приведен код контроллера для нажатия кнопки :

 func buttonClicked(date: Date) {
    let timePicker = EditTimeHelper.createTimePickerAndToolbar(displayDate: date)
    self.view.addSubview(timePicker)
}
 

Код для пользовательского представления в отдельном классе EditTimeHelper:

   static func createTimePickerAndToolbar(displayDate: Date) -> UIView {
        let pickerView = UIView(frame: CGRect(x: 0, y: UIScreen.main.bounds.height - 300, width: UIScreen.main.bounds.width, height: 300))
        let timePicker = createTimePicker(displayDate: displayDate)
        pickerView.addSubview(timePicker)
        let toolbar = createUIToolBar()
        pickerView.addSubview(toolbar)
        return pickerView
    }
    
    static func createTimePicker(displayDate: Date) -> UIDatePicker {
        let timePicker:UIDatePicker = UIDatePicker()
        timePicker.datePickerMode = UIDatePicker.Mode.time
        timePicker.date = displayDate
        timePicker.minuteInterval = 15
        if #available(iOS 13.4, *) {
            timePicker.preferredDatePickerStyle = .wheels
        } else {
            // Fallback on earlier versions where time picker is wheels style by default.
        }
        timePicker.addTarget(self, action: #selector(timeChanged(_:)), for: UIControl.Event.valueChanged)
        timePicker.backgroundColor = .white
        timePicker.frame = CGRect(x: 0, y: UIScreen.main.bounds.height - 200, width: UIScreen.main.bounds.width, height: 200)
        return timePicker
    }
    
    private static func createUIToolBar() -> UIToolbar {
        let pickerToolbar = UIToolbar()
        pickerToolbar.autoresizingMask = .flexibleHeight
        
        //customize the toolbar
        pickerToolbar.barStyle = .default
        pickerToolbar.barTintColor = UIColor.black
        pickerToolbar.backgroundColor = UIColor.white
        pickerToolbar.isTranslucent = false
        
        pickerToolbar.frame = CGRect(x: 0, y: UIScreen.main.bounds.height - 300, width: UIScreen.main.bounds.width, height: 100)
        // add buttons
        let cancelButton = UIBarButtonItem(barButtonSystemItem: .cancel, target: self, action: #selector(cancelBtnClicked(_:)))
        cancelButton.tintColor = UIColor.white
        let flexSpace = UIBarButtonItem(barButtonSystemItem: .flexibleSpace, target: nil, action: nil)
        let doneButton = UIBarButtonItem(barButtonSystemItem: .done, target: self, action: #selector(doneBtnClicked(_:)))
        doneButton.tintColor = UIColor.white
        
        //add the items to the toolbar
        pickerToolbar.items = [cancelButton, flexSpace, doneButton]
        return pickerToolbar
    }
    
    @objc func timeChanged(_ sender: UIDatePicker) {
       
    }
    
    @objc func cancelBtnClicked(_ button: UIBarButtonItem?) {
        
    }
    
    @objc func doneBtnClicked(_ button: UIBarButtonItem?) {
        
    }
 

Есть идеи, что я делаю не так и не вижу пользовательского представления?

Если я позвоню EditTimeHelper.createTimePicker(displatDate: date) , то увижу средство выбора времени, но я хочу добавить панель инструментов поверх него.

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

введите описание изображения здесь

Комментарии:

1. Ваш метод, создающий средство выбора, объявлен статическим. Нет экземпляра self , который можно было бы назначить вашему средству выбора даты.

Ответ №1:

Причина, по которой вы не видите средство выбора и панель инструментов, заключается в том, что вы неправильно расположили средство выбора времени и панель инструментов. Обратите внимание на эти две строки:

 timePicker.frame = CGRect(x: 0, y: UIScreen.main.bounds.height - 200, width: UIScreen.main.bounds.width, height: 200)
// and
pickerToolbar.frame = CGRect(x: 0, y: UIScreen.main.bounds.height - 300, width: UIScreen.main.bounds.width, height: 100)
 

Поскольку это подвиды pickerView , координаты относятся к верхнему левому углу pickerView , а не к верхнему левому углу экрана. Вместо этого вы должны сделать

 timePicker.frame = CGRect(x: 0, y: 100, width: UIScreen.main.bounds.width, height: 200)
// and
pickerToolbar.frame = CGRect(x: 0, y: 0, width: UIScreen.main.bounds.width, height: 100)
 

Теперь вы должны увидеть панель инструментов и средство выбора времени.

Однако с вашим кодом есть и другие проблемы. timeChanged Во-первых, cancelBtnClicked и doneBtnClicked не будет вызван. Вы добавили self в качестве цели элементы кнопок панели и средство выбора, но, поскольку вы находитесь в статическом методе, self относится к самому классу. Когда пользователь нажимает кнопку готово, он попытается вызвать метод, вызываемый doneBtnClicked в классе, а не в конкретном экземпляре. Но у класса нет такого метода! Объявленный doneBtnClicked вами метод является методом экземпляра, доступным только для экземпляров.

Во-вторых, вы даете этим взглядам фиксированные позиции. Это означает, что макет будет выглядеть очень странно, когда пользователь поворачивает экран. Просто используйте автозапуск!

Вы можете сделать timeChanged cancelBtnClicked и doneBtnClicked все static такое, но гораздо лучший способ-просто создать собственный UIView подкласс. Вот пример, в качестве отправной точки:

 class TimePickerToolBarView: UIView {
    override init(frame: CGRect) {
        super.init(frame: frame)
        commonInit()
    }
    
    required init?(coder: NSCoder) {
        super.init(coder: coder)
        commonInit()
    }
    
    private func commonInit() {
        let timePicker = createTimePicker()
        addSubview(timePicker)
        let toolBar = createUIToolBar()
        addSubview(toolBar)
        timePicker.translatesAutoresizingMaskIntoConstraints = false
        toolBar.translatesAutoresizingMaskIntoConstraints = false
        NSLayoutConstraint.activate([
            toolBar.heightAnchor.constraint(equalToConstant: 44),
            toolBar.topAnchor.constraint(equalTo: topAnchor),
            toolBar.leftAnchor.constraint(equalTo: leftAnchor),
            toolBar.rightAnchor.constraint(equalTo: rightAnchor),
            timePicker.leftAnchor.constraint(equalTo: leftAnchor),
            timePicker.rightAnchor.constraint(equalTo: rightAnchor),
            timePicker.bottomAnchor.constraint(equalTo: bottomAnchor),
            timePicker.topAnchor.constraint(equalTo: toolBar.bottomAnchor),
        ])
    }
    
    private func createTimePicker() -> UIDatePicker {
        let timePicker:UIDatePicker = UIDatePicker(frame: .zero)
        timePicker.datePickerMode = UIDatePicker.Mode.time
        timePicker.minuteInterval = 15
        if #available(iOS 13.4, *) {
            timePicker.preferredDatePickerStyle = .wheels
        } else {
            // Fallback on earlier versions where time picker is wheels style by default.
        }
        timePicker.addTarget(self, action: #selector(timeChanged(_:)), for: UIControl.Event.valueChanged)
        timePicker.backgroundColor = .white
        return timePicker
    }
    
    private func createUIToolBar() -> UIToolbar {
        let pickerToolbar = UIToolbar(frame: .zero)
        
        //customize the toolbar
        pickerToolbar.barStyle = .default
        pickerToolbar.barTintColor = UIColor.black
        pickerToolbar.backgroundColor = UIColor.white
        pickerToolbar.isTranslucent = false
        // add buttons
        let cancelButton = UIBarButtonItem(barButtonSystemItem: .cancel, target: self, action: #selector(cancelBtnClicked(_:)))
        cancelButton.tintColor = UIColor.white
        let flexSpace = UIBarButtonItem(barButtonSystemItem: .flexibleSpace, target: nil, action: nil)
        let doneButton = UIBarButtonItem(barButtonSystemItem: .done, target: self, action: #selector(doneBtnClicked(_:)))
        doneButton.tintColor = UIColor.white
        
        //add the items to the toolbar
        pickerToolbar.items = [cancelButton, flexSpace, doneButton]
        return pickerToolbar
    }
    
    @objc func timeChanged(_ sender: UIDatePicker) {
       
    }
    
    @objc func cancelBtnClicked(_ button: UIBarButtonItem?) {
        
    }
    
    @objc func doneBtnClicked(_ button: UIBarButtonItem?) {
        
    }
}