当前位置: 代码迷 >> 综合 >> iOS开发笔记 下拉刷新,自定义UIControl
  详细解决方案

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

热度:116   发布时间:2023-10-17 13:14:32.0

自定义下载刷新分析: 

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 = truecase .pulling: messageLable.text = "释放刷新"// 旋转箭头UIView.animateWithDuration(0.25, animations: { () -> Void inself.arrowImageView.transform = CGAffineTransformMakeRotation(CGFloat(M_PI))})case .loading: messageLable.text = "加载中"UIView.animateWithDuration(0.25, animations: { () -> Void in// 让加载的view停留一下var inset = self.scrollView!.contentInsetinset.top = inset.top + 50self.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的contentOffsetscrollView?.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// 停留一下viewvar inset = self.scrollView!.contentInsetinset.top = inset.top - 50self.scrollView?.contentInset = inset})}// 修改标记回到正常状态status = .Nomal}// MARK: 2.添加子控件和设置子控件约束private func setUpUI() {// 自定义子控件backgroundColor = UIColor.clearColor()// 设置宽高var frame = self.frameframe.size = CGSizeMake(kUIScreenWidth, 50)frame.origin.y = -50self.frame = frame// 添加控件addSubview(arrowImageView)addSubview(messageLable)addSubview(loadingView)// 设置约束loadingView.snp_makeConstraints { (make) -> Void inmake.centerX.equalTo(self.snp_centerX).offset(-30)make.centerY.equalTo(self.snp_centerY)}arrowImageView.snp_makeConstraints { (make) -> Void inmake.centerX.equalTo(self.snp_centerX).offset(-30)make.centerY.equalTo(self.snp_centerY)}messageLable.snp_makeConstraints { (make) -> Void inmake.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是加载数据时调用loadDatarefreshView.addTarget(self, action: "loadData", forControlEvents: UIControlEvents.ValueChanged)


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

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

  相关解决方案