写一个可以快速弹出多种滚轮选择器(PickerView)的小工具

使用示例效果

TextField使用示例

按钮使用示例(gif效果不满意<####>)

可以简单快速的实现上图中的效果

使用方法

1. TextField支持xib和代码生成使用, 只需调用一个方法, 设置选择的数据, 和默认选中的项(可选设置),可以设置是否在滚动的时候自动填充选中的值, 然后是在closure中处理点击完成的响应

2. 按钮(点击事件)中的使用, 只需要在相应的点击事件中使用UsefulPickerView的class方法即可, 这些方法和TextField的参数和使用完全相同, 多的一个效果就是点击背景会移除选择器

写一个可以快速弹出多种滚轮选择器(PickerView)的小工具_第1张图片

实现思路分析

  1. TextField的实现就比较的方便, 因为系统默认的是点击的时候弹出键盘, 且允许我们修改他的inputView, 所以只需要将TextField的inputView设置为我们想要弹出的pickerView即可.
  2. TextField同时被设置为不响应输入和不显示输入的光标, 这个效果, 只需要重写一个方法即可实现.
  3. 为TextField添加生成PickerView的方法, 最初笔者是在他的初始化的时候就初始化并且设置了他的inputView为需要的PickerView, 但是后来考虑到, 只需要在用户点击了输入框, 即开始编辑的代理方法中设置就好,然后为了避免过多的消耗, 在编辑结束代理方法中, 销毁了inputView.
  4. 最初是在TextField中实现的pickerView的代理方法, 但是后来考虑到按钮的使用的时候也需要实现这些代理方法, 所以就将PickerView和ToolBar单独抽出来了, 便于复用和代码分离.
  5. 因为TextField和pickerView的代理方法分开了, 要实现在用户滚动的时候同步设置选中的数据到TextField中就需要使用代理(Closure)将pickerView选中的数据传递给TextField, 所以 多了一个协议PickerViewDelegate
  6. ToolBar这部分比较简单, 只需要一个取消和确定按钮以及显示标题的Label即可, 同时需要提供给外界响应点击事件的方法(代理或者Closure)
  7. PickerView的实现就稍微要复杂一些, 因为要处理单列数据, 多列不关联数据, 多列关联数据, 城市选择, 日期选择.
  8. 需要实现PickerView相关的代理方法来设置数据, 显示数据和响应选中的数据, 在这些方法里面笔者分别使用了switch来对不同的显示方式(单列数据, 多列不关联数据…)进行了类似的处理.
  9. 关于参数的数组的使用问题, 最初是打算用NSArray来实现, 因为 单列数据中存的是String, 多列数据中存的是数组, 多列关联数据中存的是数组和字典, 所以用NSA仍然有来实现比较方便 , 但是还是想使用swift的Array, 所以就有了使用 [Any], 这种数组的想法, 但是这样就不能利用IDE来检测输入的数据格式是否正确, 所以就单独把每一中情况都使用了一个数组来实现比较的方便和安全.
    10.使用按钮弹出选择器的时候, 因为不像TextField那样本身就可以弹出视图, 所以这里选择了使用当前的Window来弹出一个View来显示pickerView, 同时在选择完成后或者点击背景后需要移除这个弹出的View, 需要使用到一点动画效果来过渡.

代码实现部分

代码比较多, 具体的请看源码地址

TextField部分

// 监听通知
    private func commonInit() {
        NSNotificationCenter.defaultCenter().addObserver(self, selector: #selector(self.didBeginEdit), name: UITextFieldTextDidBeginEditingNotification, object: self)
        NSNotificationCenter.defaultCenter().addObserver(self, selector: #selector(self.didEndEdit), name: UITextFieldTextDidEndEditingNotification, object: self)
    }
    // 开始编辑添加pickerView
    func didBeginEdit()  {
        let pickerView = setUpPickerClosure?()
        pickerView?.delegate = self
        inputView = pickerView
    }
    // 编辑完成销毁pickerView
    func didEndEdit() {
        inputView = nil
    }
    // 不要显示输入光标
    override public func caretRectForPosition(position: UITextPosition) -> CGRect {
        return CGRectZero
    }

        self.autoSetSelectedText = autoSetSelectedText

        // 保存在这个closure中, 在开始编辑的时候在执行, 避免像之前在这里直接初始化pickerView, 每个SelectionTextField在调用这个方法的时候就初始化pickerView,当有多个pickerView的时候就很消耗内存
        setUpPickerClosure = {() -> PickerView in

            return PickerView.singleColPicker(toolBarTitle, singleColData: data, defaultIndex: defaultSelectedIndex, cancelAction: {[unowned self] in

                    self.endEditing(true)

                }, doneAction: {[unowned self] (selectedIndex: Int, selectedValue: String) -> Void in

                    doneAction?(textField:self, selectedIndex: selectedIndex, selectedValue: selectedValue)
                    self.endEditing(true)

                })

UsefulPickerView. 处理弹出和移除view


    private func showPicker() {
        // 通过window 弹出view
        let window = UIApplication.sharedApplication().keyWindow
        guard let currentWindow = window else { return }
        currentWindow.addSubview(self)

        UIView.animateWithDuration(0.25, animations: {[unowned self] in
            self.backgroundColor = UIColor(red: 0.0, green: 0.0, blue: 0.0, alpha: 0.1)
            self.pickerView.frame = self.showFrame
        }, completion: nil)

            func hidePicker() {
        // 把self从window中移除
        UIView.animateWithDuration(0.25, animations: { [unowned self] in
            self.backgroundColor = UIColor.clearColor()
            self.pickerView.frame = self.hideFrame

        }) {[unowned self] (_) in
            self.removeFromSuperview()
        }
    }
    }

pickerView的代码就很多了,这里就不贴出来了.

详情和Demo请看源码源码地址, 如果您觉得有帮助,不妨给个star鼓励一下,欢迎关注, 欢迎交流

你可能感兴趣的:(ios,swift,textfield,pickerView,inputView)