iOS开发笔记>> 下拉刷新,自定义UIControl

来源:互联网 发布:阿里云 oss cdn https 编辑:程序博客网 时间:2024/05/21 10:11

自定义下载刷新分析: 

1. 系统的下拉刷新 UIRefreshControl , 没有继承系统的下拉刷新, 而继承UIControl 

2. 自定义UIControl, 系统的下拉刷新默认有宽和高, 自定义的时候在init构造函数中设置固定的宽和高和y值

3. 添加子控件(菊花, 文字一些控件)设置约束

4. 下拉刷新线索: contentOffset. y值发生变化时, 对应的效果才会变化

5. 使用KVO监听 contentOffset 这个属性值的改变

6. 把监听方法移动到自定义的UIControl里

7. 分析下拉刷新的三种状态: 正常状态, 释放状态, 加载数据状态

8. 结合 contentOffset. y 和 UISrollView的dragging 这个属性来分析临界值

9. 记录这个状态值得改变, 分别实现对应的效果

10. 优化 - 用一个标记来排除状态的多次改变(这里用的是枚举)

11. 根据效果遇到一些小bug:

1. 加载中的时候视图下沉一下 

2. 加载数据需要调用UIControl 的 sendActionsForControlEvents 方法 

3. 实现一下加载完成后恢复视图的问题

 

下面直接上swift的代码(OC的话思路是一样的)

自定义CNRefreshView

////  CNRefreshView.swift//  Sina////  Created by 晟楠 on 16/5/4.//  Copyright © 2016年 晟楠. All rights reserved.//import UIKit// 记录状态的枚举enum CNRefreshStatus: Int {        /// 正常状态    case Nomal = 1        /// 释放去加载数据状态    case pulling = 2        /// 加载数据状态    case loading = 3    }class CNRefreshView: UIControl {    /// UIScrollView类型的属性    var scrollView: UIScrollView?        /// 记录状态的属性    var status: CNRefreshStatus = .Nomal {                didSet {                        // 统一处理事件            switch status {                            case .Nomal: messageLable.text = "下拉刷新"                                UIView.animateWithDuration(0.25, animations: { () -> Void in                                        // 恢复箭头                    self.arrowImageView.transform = CGAffineTransformIdentity                })                                // 显示箭头                arrowImageView.hidden = false                                // 停止菊花转动                loadingView.stopAnimating()                                // 隐藏菊花                loadingView.hidden = true                                            case .pulling: messageLable.text = "释放刷新"                                // 旋转箭头                UIView.animateWithDuration(0.25, animations: { () -> Void in                                        self.arrowImageView.transform = CGAffineTransformMakeRotation(CGFloat(M_PI))                })                            case .loading: messageLable.text = "加载中"                            UIView.animateWithDuration(0.25, animations: { () -> Void in                                        // 让加载的view停留一下                    var inset = self.scrollView!.contentInset                                        inset.top = inset.top + 50                                        self.scrollView?.contentInset = inset                })                                // 隐藏箭头                arrowImageView.hidden = true                                // 菊花开启                loadingView.startAnimating()                                // 菊花显示                loadingView.hidden = false                                // 是加载数据状态要去加载数据                // 根据事件去触发方法                sendActionsForControlEvents(UIControlEvents.ValueChanged)            }        }    }        // MARK: - 1.重写父类构造函数    // 需要制定布局    override init(frame: CGRect) {              super.init(frame: frame)        // 添加子控件和设置子控件约束        setUpUI()    }        required init?(coder aDecoder: NSCoder) {        fatalError("init(coder:) has not been implemented")    }        // MARK: 子控件添加到父控件上回调用此方法    override func willMoveToSuperview(newSuperview: UIView?) {                super.willMoveToSuperview(newSuperview)                printLog(newSuperview)                // 转换成UIScrollView, 集成UIScrollView的子类都可以用        if newSuperview is UIScrollView {                        scrollView = newSuperview as? UIScrollView                        // MARK: - KVO监听tableView的contentOffset            scrollView?.addObserver(self, forKeyPath: "contentOffset", options: NSKeyValueObservingOptions.New, context: nil)        }            }        // MARK: - 实现KVO要监听的方法    override func observeValueForKeyPath(keyPath: String?, ofObject object: AnyObject?, change: [String : AnyObject]?, context: UnsafeMutablePointer<Void>) {                // 判断dragging进行更改标记        if scrollView!.dragging {                        if scrollView?.contentOffset.y < -140 && status == .Nomal {                                status = .pulling                            } else if scrollView?.contentOffset.y >= -140 && status == .pulling {                                status = .Nomal            }                    } else {                        if scrollView?.contentOffset.y < -140 && status == .pulling {                                status = .loading                            }                    }    }        // MARK: - 数据加载完成后调用    func endRefreshing() {                if status == .loading {                        // 让视图位置恢复            UIView.animateWithDuration(0.25, animations: { () -> Void in                                // 停留一下view                var inset = self.scrollView!.contentInset                                inset.top = inset.top - 50                                self.scrollView?.contentInset = inset                            })                    }                // 修改标记回到正常状态        status = .Nomal    }        // MARK: 2.添加子控件和设置子控件约束    private func setUpUI() {                // 自定义子控件        backgroundColor = UIColor.clearColor()                // 设置宽高        var frame = self.frame                frame.size = CGSizeMake(kUIScreenWidth, 50)                frame.origin.y = -50                self.frame = frame                // 添加控件        addSubview(arrowImageView)                addSubview(messageLable)                addSubview(loadingView)                // 设置约束        loadingView.snp_makeConstraints { (make) -> Void in                        make.centerX.equalTo(self.snp_centerX).offset(-30)                        make.centerY.equalTo(self.snp_centerY)                    }                arrowImageView.snp_makeConstraints { (make) -> Void in                        make.centerX.equalTo(self.snp_centerX).offset(-30)                        make.centerY.equalTo(self.snp_centerY)        }                messageLable.snp_makeConstraints { (make) -> Void in                        make.centerY.equalTo(self.snp_centerY)                        make.left.equalTo(arrowImageView.snp_right).offset(-5)        }                 }    // MARK: 3. 懒加载控件    // 箭头    private lazy var arrowImageView: UIImageView = {               let img = UIImageView()                img.image = UIImage(named: "tableview_pull_refresh")                return img            }()        // 菊花    private lazy var indicatorImageView: UIImageView = {                let img = UIImageView()                img.image = UIImage(named: "tableview_loading")                return img            }()        // 提示语    private lazy var messageLable: UILabel = {               let lable = UILabel()                lable.text = "下拉刷新"                return lable            }()        private lazy var loadingView: UIActivityIndicatorView = UIActivityIndicatorView(activityIndicatorStyle: UIActivityIndicatorViewStyle.Gray)}
控制器CNHomeTableViewController, 只需要做懒加载, 监听, 添加即可

// 下拉刷新    private lazy var refreshView: CNRefreshView = CNRefreshView()

// 添加下拉刷新视图            tableView.addSubview(refreshView)

// 监听refreshView,当refreshView是加载数据时调用loadData            refreshView.addTarget(self, action: "loadData", forControlEvents: UIControlEvents.ValueChanged)


在刷新数据之后调用 endRefreshing 方法停止即可
// 停止下拉刷新            self.refreshView.endRefreshing()

代码如有哪里不妥可以加关注私信或评论给我, 谢谢

0 0
原创粉丝点击