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動畫數秒,然後回彈。

相關文章
相關標籤/搜索