iOS swift带动画下拉刷新

一、参考MJRefresh下拉刷新效果,思考怎么自定义实现一个带spinner动画的下拉刷新控件。

- (void)prepare
{
    [super prepare];
    
    // 设置普通状态的动画图片
    NSMutableArray *idleImages = [NSMutableArray array];
    for (NSUInteger i = 1; i<=60; i++) {
        UIImage *image = [UIImage imageNamed:[NSString stringWithFormat:@"dropdown_anim__000%zd", i]];
        [idleImages addObject:image];
    }
     [self setImages:idleImages forState:MJRefreshStateIdle];
    
    // 设置即将刷新状态的动画图片(一松开就会刷新的状态)
    NSMutableArray *refreshingImages = [NSMutableArray array];
    for (NSUInteger i = 1; i<=3; i++) {
        UIImage *image = [UIImage imageNamed:[NSString stringWithFormat:@"dropdown_loading_0%zd", i]];
        [refreshingImages addObject:image];
    }
    [self setImages:refreshingImages forState:MJRefreshStatePulling];
    
    // 设置正在刷新状态的动画图片
    [self setImages:refreshingImages forState:MJRefreshStateRefreshing];
}
复制代码

二、思考怎么实现:

  • 下拉过程的渐变更画该怎么样?swift

    • 使用像MJRefresh那样的逐帧图方案?须要跟UI要不少图,并且占用APP空间,不合适公司项目。除非要挂个很是复杂的动画图。markdown

    • 给spinner加个progress属性?根据progress值来设置spinner红圆的的填充效果?发现spinner没有一个渐变过程,所以须要思考其余方案。ide

  • 替代方案:在spinner上面盖一个环形的view,使用贝塞尔曲线来根据下拉距离来填充环形颜色。下拉距离小于临界点,显示环形view,隐藏spinner,开始动画的时候,隐藏环形view,显示spinner。oop

final class RefreshProgressView: UIView {
    var progess: CGFloat = 0.0
    private let shapeLayer = CAShapeLayer()
    override init(frame: CGRect) {
        super.init(frame: frame)
        seup(rect: frame)
    }

    required init?(coder aDecoder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }

    func seup(rect: CGRect) {
        shapeLayer.frame = CGRect.init(x: 0, y: 0, width: rect.size.width, height: rect.size.height)
        shapeLayer.lineWidth = XOSpinner.pathLineWidth
        shapeLayer.fillColor = UIColor.clear.cgColor
        shapeLayer.strokeColor = UIColor.tkRed500.cgColor
        shapeLayer.strokeEnd = 0

        let center: CGPoint = CGPoint.init(x: rect.size.width/2, y: rect.size.height/2)
        let bezierPath: UIBezierPath = UIBezierPath(arcCenter: center,
                                                    radius: (rect.size.width - XOSpinner.pathLineWidth)/2,
                                                    startAngle: CGFloat(0.5 * Double.pi),
                                                    endAngle: CGFloat(2.5 * Double.pi),
                                                    clockwise: true)
        shapeLayer.path = bezierPath.cgPath
        layer.addSublayer(shapeLayer)
    }

    func setProgress(value: CGFloat) {
        progess = value
        shapeLayer.strokeEnd = progess
    }
}
复制代码
  • 整体结构以及动画的临界点:

  • UIScrollView+Extension中,使用运行时方式,添加headerRefresh属性,这样就能在设置tableView的时候,添加下拉刷新的事件。(swift扩展中怎么用运行时添加属性:可参考Stored Properties In Swift Extensions
public var headerRefresh: XOPullDownToRefresh? {
        get {
            return objc_getAssociatedObject(self, &refreshHeaderKey) as? XOPullDownToRefresh
        }
        set(newValue) {
            guard let newValue = newValue, newValue != headerRefresh else { return }
            headerRefresh?.removeFromSuperview()
            insertSubview(newValue, at: 0)
            objc_setAssociatedObject(self, &refreshHeaderKey, newValue, .OBJC_ASSOCIATION_RETAIN_NONATOMIC)
        }
    }
复制代码
tableView.headerRefresh = XOPullDownToRefresh(refreshingTarget: self, refreshingAction: #selector(refreshAction))
复制代码
  • 关于怎么设置XOPullDownToRefresh中的scrollView为所在的tableView
override public func willMove(toSuperview newSuperview: UIView?) {
        super.willMove(toSuperview: newSuperview)
        guard let newSuperview = newSuperview, let scrollView = newSuperview as? UIScrollView else { return }
        removeObservers()
        scrollView.alwaysBounceVertical = true
        scrollViewOriginalInset = scrollView.contentInset
        self.scrollView = scrollView
        addObservers()
    }
复制代码
  • 拿到scrollView之后,使用KVO监听他的contentOffset,根据contentOffset.y去设置不一样的状态:idlepullingwillRefresh, refreshing动画

  • 下拉:位置未超过临界点,填充环圈颜色的过程。ui

  • 下拉:位置已经超过临界点,启动spinner动画。

  • 松手:位置未超过临界点,直接回弹。

  • 松手:位置已经超过临界点,持续spinner动画数秒,然后回弹。

相关文章
相关标签/搜索