美文网首页ios初级篇vxg的iOS开发买不来的iOS实用技巧
写一个可以快速弹出多种滚轮选择器(PickerView)的小工具

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

作者: ZeroJ | 来源:发表于2016-04-26 22:43 被阅读3998次

    使用这个小框架可以快速的完成注册页面或者个人信息页面的选择项

    使用示例效果

    TextField使用示例

    TextField使用示例.gif

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

    按钮使用示例.gif

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


    使用方法

    设置数据.png

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

    TextField使用.png

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

    实现思路分析

    1. TextField的实现就比较的方便, 因为系统默认的是点击的时候弹出键盘, 且允许我们修改他的inputView, 所以只需要将TextField的inputView设置为我们想要弹出的pickerView即可.
    1. TextField同时被设置为不响应输入和不显示输入的光标, 这个效果, 只需要重写一个方法即可实现.
    2. 为TextField添加生成PickerView的方法, 最初笔者是在他的初始化的时候就初始化并且设置了他的inputView为需要的PickerView, 但是后来考虑到, 只需要在用户点击了输入框, 即开始编辑的代理方法中设置就好,然后为了避免过多的消耗, 在编辑结束代理方法中, 销毁了inputView.
    3. 最初是在TextField中实现的pickerView的代理方法, 但是后来考虑到按钮的使用的时候也需要实现这些代理方法, 所以就将PickerView和ToolBar单独抽出来了, 便于复用和代码分离.
    4. 因为TextField和pickerView的代理方法分开了, 要实现在用户滚动的时候同步设置选中的数据到TextField中就需要使用代理(Closure)将pickerView选中的数据传递给TextField, 所以 多了一个协议PickerViewDelegate
    5. ToolBar这部分比较简单, 只需要一个取消和确定按钮以及显示标题的Label即可, 同时需要提供给外界响应点击事件的方法(代理或者Closure)
    6. PickerView的实现就稍微要复杂一些, 因为要处理单列数据, 多列不关联数据, 多列关联数据, 城市选择, 日期选择.
    7. 需要实现PickerView相关的代理方法来设置数据, 显示数据和响应选中的数据, 在这些方法里面笔者分别使用了switch来对不同的显示方式(单列数据, 多列不关联数据...)进行了类似的处理.
    8. 关于参数的数组的使用问题, 最初是打算用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
        }
    
    
    
            // 保存在这个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鼓励一下,欢迎关注, 欢迎交流

    相关文章

      网友评论

      • phooo:请问如何把 datepickview 如何改成 dateAndTimepickview ?
      • 科24:为什么我用3.0里面报很多错误啊
      • 科24:不支持3.0了吗?
      • 常绿箩:给你点个星 :smile:
      • 93a65d8fa5ad:請問必須要使用 [String] 才能??
        是否能幫忙改成 [Int] 也能呢?
        93a65d8fa5ad:@ZeroJ 新手比較不懂怎麼操作 ,以理解搞定!
        ZeroJ:@s2339956 对啊, 不懂为什么需要int, Int转String很方便的
      • xhzth70911:我光给 ["北京", "通州"],运行起来以后,正常显示北京通州, 但是滚动北京,就报错了,求大神赐教
        ZeroJ:@安东街 这个是个bug, 已经修复了
      • xhzth70911: 报这个错fatal error: Index out of range, 怎么给成显示2个的
      • xhzth70911:请教一下UsefulPickerView.showCitiesPicker("省市区选择", defaultSelectedValues: ["四川", "成都", "郫县"]) {[unowned self] (selectedIndexs, selectedValues) in
        // 处理数据
        let combinedString = selectedValues.reduce("", combine: { (result, value) -> String in
        result + " " + value
        })

        self.selectedDataLabel.text = "选中了第\(selectedIndexs)行----选中的数据为\(combinedString)"

        }
        这行代码里,defaultSelectedValues: ["四川", "成都", "郫县"], 我改成了 ["北京", "通州"],直接崩了. 怎么改成啊
        ZeroJ:@安东街 加这个 573645936
      • e5fb1e513efd:有 OC 的吗
        ZeroJ:@笑到永远 朋友, 这个oc的我记得之前写过对应版本的了, ZJUserfulPickerView
        51a9120806cc:github找了好多,没有你的这个用的方便,舒服,找到的有些问题,可惜没有OC的,已start
        ZeroJ:@爱吃土豆的程序媛 抱歉抱歉 , 这个我没有写oc版的, 不过github上有很多类似功能的oc的,你可以找找看
      • 031a00324437:这是swift写的吗
        ZeroJ:@噤址 嗯,是的
      • jswift:多谢分享 :smile:, 持续关注大神
        ZeroJ:@iOS小学生 :grin:对的,使用比较方便
        iOS小学生:好东西啊,PickerView变简单了
        ZeroJ:@jswift 只是分享一些比较实用的东西, 还不是大神 :smile:

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

      本文链接:https://www.haomeiwen.com/subject/cxtcrttx.html