Day19 - 自定義下拉刷新

效果:

最終效果

<br />
<br />

1、UI布局

布局

<br />

2、代碼實現,為了Controller中的代碼不那么臃腫,我們稍微封裝一下代碼

2.1 封裝dataSource

  • 1 新建一個類,繼承NSobject
  • 2 導入UITableViewDatasource
  • 3 實現代理方法
  • 4 封裝一個對外公開的類方法:此時應該至少需要Identifier、數據源、有沒有Section、回調(閉包)
  • 5 提供一個結構體
  • 6 提供一個獲取數據(模型)的方法
    代碼如下
//
//  TBDataSource.swift
//  CustomPullToRefresh
//
//  Created by ios on 16/9/26.
//  Copyright ? 2016年 ios. All rights reserved.
//

import UIKit
/**
 設置Section樣式,默認 Single
 */
public enum TBSectionStyle : Int {
    
    ///Default 默認沒有多個Section
    case Section_Single
    /// 有多個Section
    case Section_Has
}


class TBDataSource: NSObject,UITableViewDataSource {
    
    private var sectionStyle : TBSectionStyle = .Section_Single
    private var data : NSArray?
    private var identifier : String = "null"
    private var cellBlock : ((cell : AnyObject, item : AnyObject) -> ())?
    
    /**
     快速創建一個數據源,需要提前注冊,數組和style要對應
     
     - parameter identifier: 標識
     - parameter data:       數據
     - parameter style:      類型
     - parameter cell:       回調
     
     - returns: 數據源對象(dataSource)
     */
    static func cellIdentifierWith(identifier : String , data : NSArray , style : TBSectionStyle , cell : ((cell : AnyObject, item : AnyObject) -> Void)) -> TBDataSource {
        let source = TBDataSource()
        
        source.sectionStyle = style
        source.data = data
        source.identifier = identifier
        source.cellBlock = cell
        
        return source
        
    }
    /**
     返回數據
     
     - parameter indexPath: indexPath
     
     - returns: 數據
     */
    private func itemWithIndexPath(indexPath : NSIndexPath) -> AnyObject{
        if sectionStyle == .Section_Single {
            return data![indexPath.row]
        }
        else{
            return data![indexPath.section][indexPath.row]
        }
    }
    
    /**
     返回有多少個Section
     
     - parameter tableView: tableView
     
     - returns: section
     */
    func numberOfSectionsInTableView(tableView: UITableView) -> Int {
        if sectionStyle == .Section_Single {
            return 1
        }
        return (data?.count)!
    }
    
    /**
     返回對應Section的rows
     
     - parameter tableView: tableView
     - parameter section:   section
     
     - returns: rows
     */
    func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int{
        if sectionStyle == .Section_Single {
            return (data?.count)!
        }else{
            return (data?[section].count)!
        }
    }
    /**
     返回cell,并用閉包把cell封裝到外面,提供樣式設置
     
     - parameter tableView: tableView
     - parameter indexPath: indexPath
     
     - returns: cell
     */
    func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
        let cell = tableView.dequeueReusableCellWithIdentifier(identifier, forIndexPath: indexPath)
        if let block = cellBlock {
            block(cell: cell, item: itemWithIndexPath(indexPath))
        }
        return cell
    }
}

<br />
封裝好DataSource之后,ViewController中聲明一個屬性,此時對cell外觀操作,都在這里處理

 /// 數據源
    private lazy var dataSource : TBDataSource = {
       let source = TBDataSource.cellIdentifierWith("iconCell", data: [["??", "??", "??", "??", "??"],["??", "??", "??", "??", "??"],["??", "??", "??", "??", "??"]], style: TBSectionStyle.Section_Has, cell: { (cell: AnyObject, item: AnyObject) -> () in
            let newCell = cell as! UITableViewCell
            let newItem = item as! String
            newCell.textLabel!.text = newItem
            newCell.textLabel?.font = UIFont(name: "Apple Color Emoji", size: 40)
            newCell.textLabel?.textAlignment = NSTextAlignment.Center
       })
        return source
    }()

<br />
聲明屬性之后,只需要執行下面的一行代碼便可以展示出數據源了

tableView.dataSource = dataSource

3、封裝動畫

  • 創建一個xib
xib
  • 創建一個類,繼承UIRefreshControl
  • 提供一個加載xib的類方法
  • 在類方法中把xib加載進來的views存入數組,便于做動畫
  • 實現動畫,這里使用transfrom,你們也可以自定義其他的動畫
    代碼試下如下:
//
//  CustomRefreshView.swift
//  CustomPullToRefresh
//
//  Created by ios on 16/9/26.
//  Copyright ? 2016年 ios. All rights reserved.
//

import UIKit
/// 自定義刷新控件
class CustomRefreshView: UIRefreshControl {

    private var xibViews : Array<UIView> = []
    private var isAnimating : Bool = false
    private var currentColorIndex = 0
    private var currentLabelIndex = 0
    static func addViewsForNib( name : String) -> CustomRefreshView{
        let content = NSBundle.mainBundle().loadNibNamed(name, owner: self, options: nil).first as! UIView
        
        let cus = CustomRefreshView()
        cus.addSubview(content)
        
        for i in 0..<content.subviews.count {
            cus.xibViews.append(content.subviews[i])
            cus.xibViews[i].layer.cornerRadius = (cus.xibViews[i].bounds.width + cus.xibViews[i].bounds.height) * 0.25
            cus.xibViews[i].clipsToBounds = true
        }
        
        return cus
    }
    
    /**
     向外面提供一個開始動畫的方法
     */
    func startAnimation(){
        animateRefreshStep1()
    }
    
    ///動畫設置 外面不需要知道,所以都設置成為私有方法
    private func animateRefreshStep1() {
        
        isAnimating = true
        
        UIView.animateWithDuration(0.1, delay: 0.0, options: UIViewAnimationOptions.CurveLinear, animations: { () -> Void in
            
            self.xibViews[self.currentLabelIndex].transform = CGAffineTransformMakeRotation(CGFloat(M_PI_4))
            self.xibViews[self.currentLabelIndex].backgroundColor = self.getNextColor()
            
            }, completion: { (finished) -> Void in
                
                UIView.animateWithDuration(0.05, delay: 0.0, options: UIViewAnimationOptions.CurveLinear, animations: { () -> Void in
                    self.xibViews[self.currentLabelIndex].transform = CGAffineTransformIdentity
                    
                    }, completion: { (finished) -> Void in
                        self.currentLabelIndex += 1
                        
                        if self.currentLabelIndex < self.xibViews.count {
                            self.animateRefreshStep1()
                        }
                        else {
                            self.animateRefreshStep2()
                        }
                })
        })
    }
    
    ///動畫設置 外面不需要知道,所以都設置成為私有方法
    private func animateRefreshStep2() {
        UIView.animateWithDuration(0.40, delay: 0.0, options: UIViewAnimationOptions.CurveLinear, animations: { () -> Void in
            
            self.xibViews[0].transform = CGAffineTransformMakeScale(1.5, 1.5)
            self.xibViews[1].transform = CGAffineTransformMakeScale(1.5, 1.5)
            self.xibViews[2].transform = CGAffineTransformMakeScale(1.5, 1.5)
            self.xibViews[3].transform = CGAffineTransformMakeScale(1.5, 1.5)
            self.xibViews[4].transform = CGAffineTransformMakeScale(1.5, 1.5)
            self.xibViews[5].transform = CGAffineTransformMakeScale(1.5, 1.5)
            self.xibViews[6].transform = CGAffineTransformMakeScale(1.5, 1.5)
            self.xibViews[7].transform = CGAffineTransformMakeScale(1.5, 1.5)
            
            }, completion: { (finished) -> Void in
                
                UIView.animateWithDuration(0.25, delay: 0.0, options: UIViewAnimationOptions.CurveLinear, animations: { () -> Void in
                    self.xibViews[0].transform = CGAffineTransformIdentity
                    self.xibViews[1].transform = CGAffineTransformIdentity
                    self.xibViews[2].transform = CGAffineTransformIdentity
                    self.xibViews[3].transform = CGAffineTransformIdentity
                    self.xibViews[4].transform = CGAffineTransformIdentity
                    self.xibViews[5].transform = CGAffineTransformIdentity
                    self.xibViews[6].transform = CGAffineTransformIdentity
                    self.xibViews[7].transform = CGAffineTransformIdentity
                    
                    }, completion: { (finished) -> Void in
                        if self.refreshing {
                            self.currentLabelIndex = 0
                            self.animateRefreshStep1()
                        }
                        else {
                            self.isAnimating = false
                            self.currentLabelIndex = 0
                            for i in 0 ..< self.xibViews.count {
                                self.xibViews[i].transform = CGAffineTransformIdentity
                                self.xibViews[i].backgroundColor = UIColor.clearColor()
                            }
                        }
                })
        })
    }
    ///動畫設置 外面不需要知道,所以都設置成為私有方法
    private func getNextColor() -> UIColor {
        var colorsArray: Array<UIColor> = [UIColor.magentaColor(), UIColor.brownColor(), UIColor.yellowColor(), UIColor.redColor(), UIColor.greenColor(), UIColor.blueColor(), UIColor.orangeColor()]
        
        if currentColorIndex == colorsArray.count {
            currentColorIndex = 0
        }
        
        let returnColor = colorsArray[currentColorIndex]
        currentColorIndex += 1
        
        return returnColor
    }
}


<br />

完成對動畫的封裝之后,Controller中的代碼如下

//
//  ViewController.swift
//  CustomPullToRefresh
//
//  Created by ios on 16/9/26.
//  Copyright ? 2016年 ios. All rights reserved.
//

import UIKit

class ViewController: UIViewController ,UITableViewDelegate{

    @IBOutlet weak var tableView: UITableView!
    
    /// 數據源
    private lazy var dataSource : TBDataSource = {
       let source = TBDataSource.cellIdentifierWith("iconCell", data: [["??", "??", "??", "??", "??"],["??", "??", "??", "??", "??"],["??", "??", "??", "??", "??"]], style: TBSectionStyle.Section_Has, cell: { (cell: AnyObject, item: AnyObject) -> () in
            let newCell = cell as! UITableViewCell
            let newItem = item as! String
            newCell.textLabel!.text = newItem
            newCell.textLabel?.font = UIFont(name: "Apple Color Emoji", size: 40)
            newCell.textLabel?.textAlignment = NSTextAlignment.Center
       })
        return source
    }()
    
    private lazy var refreshControl : CustomRefreshView = CustomRefreshView.addViewsForNib("RefreshContents")
    
    private var isAnimating : Bool = false
    
    var timer: NSTimer!
    
    override func viewDidLoad() {
        super.viewDidLoad()
        
        tableView.dataSource = dataSource
        tableView.delegate = self
        tableView.rowHeight = 60
        
        tableView.addSubview(refreshControl)
        
    }
    
    func scrollViewDidEndDecelerating(scrollView: UIScrollView) {
        if refreshControl.refreshing {
            if !isAnimating {
                doSomething()
                refreshControl.startAnimation()
            }
        }
    }
    
    /**
     開啟定時器
     */
    private func doSomething() {
        timer = NSTimer.scheduledTimerWithTimeInterval(5, target: self, selector: #selector(ViewController.endedOfWork), userInfo: nil, repeats: true)
    }
    /**
     定時器結束,關閉動畫
     */
    @objc private func endedOfWork() {
        refreshControl.endRefreshing()
        timer.invalidate()
        timer = nil
    }
}


本文Demo

Demo - CustomPullToRefresh

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容