效果:
最終效果
<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