美文网首页
Swift_下拉刷新

Swift_下拉刷新

作者: 走停2015_iOS开发 | 来源:发表于2020-05-13 16:18 被阅读0次
  • 视图偏移量 内边距
  • 消息发送
  • 代码layout布局
WeChat3f9f4570329de1a1cfb7b3cdea6dbb8c.png
1. 负责刷新相关的逻辑处理
///刷新状态到达临界点
private let HWRefreshOffset:CGFloat = 60.0

/// 刷新状态
enum HWRefreshState {
    case Normal //普通
    case Pulling //超过临界点,没有放手
    case WillRefresh //超过临界点 并且放手
}

class HWRefreshControl: UIControl {
    
    //滚动视图的父视图 下拉刷新控件 适用于 tableView/collectionView
    private weak var scrollView:UIScrollView?
    
    private lazy var refreshView:HWRefreshView = HWRefreshView.refreshView()
    
    
    
    init() {
        super.init(frame: CGRect())
        
        setupUI()
    }
    
    required init?(coder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }
    
    //当添加到俯视图的时候 newSuperview是父视图
    override func willMove(toSuperview newSuperview: UIView?) {
        super.willMove(toSuperview:newSuperview)
        //判断父视图的类型
        guard let sv = newSuperview as? UIScrollView else {
            return;
        }
        //记录父视图
        scrollView = sv
        
        //KVO 监听父视图的偏移
        scrollView?.addObserver(self, forKeyPath:"contentOffset", options: [], context: nil)
    }
    //从父视图移除
    override func removeFromSuperview() {
        //移除KVO监听
        superview?.removeObserver(self, forKeyPath: "contentOffset")
        superview?.removeFromSuperview()
    }
    //监听方法
    override func observeValue(forKeyPath keyPath: String?, of object: Any?, change: [NSKeyValueChangeKey : Any]?, context: UnsafeMutableRawPointer?) {
        guard let sv = scrollView else {
           return
        }
        //初始化高度是0
        let height = -(sv.contentInset.top + sv.contentOffset.y)
         print(sv.contentInset)
        if height<0{
            return
        }
        
        //可以根据高度的设置刷新控件的frame
        //y:不能为0 因为self参考的父视图是scollView的content
        self.frame = CGRect(x: 0, y: -height, width:sv.bounds.width , height: height)
        
        //判断临界点 只需要判断一次 需要通过刷新状态
        if sv.isDragging {
            if height > HWRefreshOffset && refreshView.refreshState == .Normal {
              refreshView.refreshState = .Pulling
            }else if(height <= HWRefreshOffset && refreshView.refreshState == .Pulling){
                refreshView.refreshState = .Normal
            }
        }else{
           //放手 --判断是否超过临界点
            if refreshView.refreshState == .Pulling {
                 //开始刷新
                 beginRefreshing()
                 //发送刷新数据事件
                sendActions(for: .valueChanged)
            }
        }
    }
    
    func beginRefreshing(){
        
       //判断父视图
        guard let sv = scrollView else {
           return
        }
        //判断是否正在刷新 如果正在刷新 直接返回
        if refreshView.refreshState == .WillRefresh {
          return
        }
        
        //设置刷新视图的状态
        refreshView.refreshState = .WillRefresh
        
        //调整表格间距
        var inset = sv.contentInset
        inset.top += HWRefreshOffset
        sv.contentInset = inset
        
    }
    func endRefreshing(){
       //判断父视图
        guard let sv = scrollView else {
           return
        }
        //判断状态 是否正在刷新 如果不是 直接返回
        if refreshView.refreshState != .WillRefresh {
           return
        }
        //设置刷新视图的状态
        refreshView.refreshState = .Normal
        //调整表格间距
        var inset = sv.contentInset
        inset.top -= HWRefreshOffset
        sv.contentInset = inset
    }
    deinit {
        
    }
}
extension HWRefreshControl{
    
    private func setupUI(){
        backgroundColor = superview?.backgroundColor
        
        //设置超出边界不显示
//        clipsToBounds = true
        
        //添加视图
        addSubview(refreshView)
        
        //自动布局
        refreshView.translatesAutoresizingMaskIntoConstraints = false
        
        addConstraints([NSLayoutConstraint(item: refreshView, attribute: .centerX, relatedBy: .equal, toItem: self, attribute: .centerX, multiplier: 1.0, constant: 0)])
        addConstraints([NSLayoutConstraint(item: refreshView, attribute: .bottom, relatedBy: .equal, toItem: self, attribute: .bottom, multiplier: 1.0, constant: 0)])
        addConstraints([NSLayoutConstraint(item: refreshView, attribute: .width, relatedBy: .equal, toItem: nil, attribute: .notAnAttribute, multiplier: 1.0, constant: refreshView.bounds.width)])
        addConstraints([NSLayoutConstraint(item: refreshView, attribute: .height, relatedBy: .equal, toItem: nil, attribute: .notAnAttribute, multiplier: 1.0, constant: refreshView.bounds.height)])
    }
}
2.刷新视图 负责刷新相关UI显示和动画
class HWRefreshView: UIView {
    
    ///刷新状态
    ///动画-0.0001 为了符合动画就近原则
    var refreshState:HWRefreshState = .Normal{
        didSet{
            switch refreshState {
            case .Normal:
                tipLable.text = "继续使劲拉"
                //显示提示图标
                tipIcon.isHidden = false
                //隐藏转圈
                indicator.stopAnimating()
                UIView.animate(withDuration: 0.25) {
                    self.tipIcon.transform = CGAffineTransform.identity
                }
            case .Pulling:
                tipLable.text = "放手就刷新"
                UIView.animate(withDuration: 0.25) {
                    self.tipIcon.transform = CGAffineTransform(rotationAngle:CGFloat(Double.pi-0.001))
                }
            case .WillRefresh:
                tipLable.text = "正在刷新中"
                
                //隐藏提示图标
                tipIcon.isHidden = true
                //显示转圈
                indicator.startAnimating()
            }
        }
    }
    ///提示文字
    @IBOutlet weak var tipIcon: UIImageView!
    ///提示图标
    @IBOutlet weak var tipLable: UILabel!
    ///指示器
    @IBOutlet weak var indicator: UIActivityIndicatorView!
    
    class func refreshView()->HWRefreshView{
        
        let nib = UINib(nibName: "HWRefreshView", bundle: nil)
        
        return nib.instantiate(withOwner: nib, options: nil)[0] as! HWRefreshView
    }
}

相关文章

网友评论

      本文标题:Swift_下拉刷新

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