子类 UIControl 来制作自定义选择器

Posted

技术标签:

【中文标题】子类 UIControl 来制作自定义选择器【英文标题】:Subclass UIControl to make custom picker 【发布时间】:2017-02-06 18:37:22 【问题描述】:

我正在尝试制作像 UIDatePicker 这样的自定义选择器控件,但使用不同的数据源来包含选择器的所有逻辑,并允许目标操作行为。

为此,我将UIControl 子类化,添加UIPickerView 并设置选择器视图的数据源和委托给子类。我的问题在于视图的大小。

我在每个设备上都使用过UIDatePicker,它的默认高度是 216,默认宽度是 320。拉伸宽度时,选择器视图不会拉伸,但拉伸高度时会拉伸。为了适应系统,我希望我的选择器的大小也一样。

我尝试为我的子类制作一个 nib 文件。我将视图调整为 320x216,添加了 UIPickerView 并将其连接为 IBOutlet。在我对init?(coder aDecoder: NSCoder) 的实现中,我设置了选择器的数据源和委托,但是当我运行我的测试应用程序时,我崩溃了,因为此时连接的UIPickerView 仍然是nil

我的目标是能够使用 init() 和在情节提要中使用它,就像使用 UIDatePicker 一样,所以我放弃了 nib 并一直试图将所有内容封装在代码中。如何将视图设置为与 UIDatePicker 相同的行为?

这是我目前的尝试(不使用笔尖,因为它必须在代码中才能在情节提要中使用):

class FWHeightPicker: UIControl 
    let pickerView: UIPickerView

    convenience init() 
        let size = CGSize(width: 320, height: 216)
        let origin = CGPoint(x: 0, y: 0)
        let frame = CGRect(origin: origin, size: size)

        self.init(frame: frame)
    

    override init(frame: CGRect) 
        pickerView = UIPickerView(frame: frame)

        super.init(frame: frame)
        commonInit()
    

    required init?(coder aDecoder: NSCoder) 
        let size = CGSize(width: 320, height: 216)
        let origin = CGPoint(x: 0, y: 0)
        let frame = CGRect(origin: origin, size: size)

        pickerView = UIPickerView(frame: frame)

        super.init(coder: aDecoder)
        commonInit()
    

    func commonInit() 
        let topConstraint = NSLayoutConstraint(item: self, attribute: .top, relatedBy: .equal, toItem: pickerView, attribute: .top, multiplier: 1, constant: 0)
        let bottomConstraint = NSLayoutConstraint(item: self, attribute: .bottom, relatedBy: .equal, toItem: pickerView, attribute: .bottom, multiplier: 1, constant: 0)
        self.addConstraints([topConstraint, bottomConstraint])

        pickerView.delegate = self
        pickerView.dataSource = self
    


extension FWHeightPicker: UIPickerViewDelegate, UIPickerViewDataSource 
// Delegate/Datasource implementations

【问题讨论】:

【参考方案1】:

您只需将您的pickerView 作为子视图添加到您的FWHeightPicker。然后,您应该使用 pickerView.translatesAutoresizingMaskIntoConstraints = false 删除 pickerView 的默认 AutoLayout 约束,以支持您想要的约束。

我已经对您的代码进行了一些尝试(为了方便起见,仅删除了扩展名)- 它工作正常,并且可以拉伸/缩小选择器的宽度和高度以适应您在方便的 init() 中定义的视图大小:

class FWHeightPicker: UIControl, UIPickerViewDelegate, UIPickerViewDataSource 

  let pickerView: UIPickerView

  convenience init() 

    let size = CGSize(width: 320, height: 216)
    let origin = CGPoint(x: 0, y: 0)
    let frame = CGRect(origin: origin, size: size)

    self.init(frame: frame)
  

  override init(frame: CGRect) 

    pickerView = UIPickerView(frame: frame)

    super.init(frame: frame)
    commonInit()
  

  required init?(coder aDecoder: NSCoder) 

    pickerView = UIPickerView()

    super.init(coder: aDecoder)
    commonInit()
  

  func commonInit() 

    pickerView.delegate = self
    pickerView.dataSource = self

    addSubview(pickerView)

    pickerView.translatesAutoresizingMaskIntoConstraints = false

    let topConstraint = NSLayoutConstraint(item: self, attribute: .top, relatedBy: .equal, toItem: pickerView, attribute: .top, multiplier: 1, constant: 0)

    let bottomConstraint = NSLayoutConstraint(item: pickerView, attribute: .bottom, relatedBy: .equal, toItem: self, attribute: .bottom, multiplier: 1, constant: 0)

    let leftConstraint = NSLayoutConstraint(item: self, attribute: .leading, relatedBy: .equal, toItem: pickerView, attribute: .leading, multiplier: 1.0, constant: 0)

    let rightConstraint = NSLayoutConstraint(item: pickerView, attribute: .trailing, relatedBy: .equal, toItem: self, attribute: .trailing, multiplier: 1.0, constant: 0)

    self.addConstraints([topConstraint, bottomConstraint, leftConstraint, rightConstraint])

  

  // Delegate/Datasource implementations
  func numberOfComponents(in pickerView: UIPickerView) -> Int 

    return 1
  

  func pickerView(_ pickerView: UIPickerView, numberOfRowsInComponent component: Int) -> Int 

    return 10
  

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

    return "row"
  

【讨论】:

以上是关于子类 UIControl 来制作自定义选择器的主要内容,如果未能解决你的问题,请参考以下文章

flowable设计器自定义自己的人员选择器

在警报级别窗口中具有自定义 inputView 的 UIControl

突出显示 UIControl 子类

UIControl 跟踪在不同 UIControl 上开始的触摸

LayUI laydate日期选择器自定义 快捷选中今天昨天 本周本月等等

LayUI laydate日期选择器自定义 快捷选中今天昨天 本周本月等等