1.下拉刷新
refreshControl = UIRefreshControl()
let otherView = UIView()
otherView.frame = CGRect(x: 0, y: 0, width: 400, height: 44)
otherView.backgroundColor = UIColor.purpleColor()
refreshControl?.addSubview(otherView)
/*
1.UIRefreshControl只要拉到一定程度無論是否松手會都觸發(fā)下拉事件
2.觸發(fā)下拉時(shí)間之后, 菊花不會自動隱藏
3.想讓菊花消失必須手動調(diào)用endRefreshing()
4.只要調(diào)用beginRefreshing, 那么菊花就會自動顯示
5.如果是通過beginRefreshing顯示菊花, 不會觸發(fā)下拉事件
*/
refreshControl?.addTarget(self, action: Selector("loadMoreData"), forControlEvents: UIControlEvents.ValueChanged)
RefreshView.swift
import UIKit
import SnapKit
class XMGRefreshControl: UIRefreshControl {
override init() {
super.init()
// 1.添加子控件
addSubview(refreshView)
// 2.布局子控件
refreshView.snp_makeConstraints { (make) -> Void in
make.size.equalTo(CGSize(width: 150, height: 50))
make.center.equalTo(self)
}
// 3.監(jiān)聽UIRefreshControl frame改變
addObserver(self, forKeyPath: "frame", options: NSKeyValueObservingOptions.New, context: nil)
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
deinit
{
removeObserver(self, forKeyPath: "frame")
}
override func endRefreshing() {
super.endRefreshing()
refreshView.stopLoadingView()
}
/// 記錄是否需要旋轉(zhuǎn)
var rotationFlag = false
// MARK: - 內(nèi)部控制方法
override func observeValueForKeyPath(keyPath: String?, ofObject object: AnyObject?, change: [String : AnyObject]?, context: UnsafeMutablePointer<Void>) {
if frame.origin.y == 0 || frame.origin.y == -64
{
// 過濾掉垃圾數(shù)據(jù)
return
}
// 判斷是否觸發(fā)下拉刷新事件
if refreshing
{
// 隱藏提示視圖, 顯示加載視圖, 并且讓菊花轉(zhuǎn)動
refreshView.startLoadingView()
return
}
// 通過觀察發(fā)現(xiàn): 往下拉Y越小, 往上推Y越大
if frame.origin.y < -50 && !rotationFlag
{
rotationFlag = true
NJLog("往上旋轉(zhuǎn)")
refreshView.rotationArrow(rotationFlag)
}else if frame.origin.y > -50 && rotationFlag
{
rotationFlag = false
NJLog("往下旋轉(zhuǎn)")
refreshView.rotationArrow(rotationFlag)
}
}
// MARK: -懶加載
private lazy var refreshView: RefreshView = RefreshView.refreshView()
}
class RefreshView: UIView {
/// 菊花
@IBOutlet weak var loadingImageView: UIImageView!
/// 提示視圖
@IBOutlet weak var tipView: UIView!
/// 箭頭
@IBOutlet weak var arrowImageView: UIImageView!
class func refreshView() -> RefreshView {
return NSBundle.mainBundle().loadNibNamed("RefreshView", owner: nil, options: nil).last as! RefreshView
}
// MARK: - 外部控制方法
/// 旋轉(zhuǎn)箭頭
func rotationArrow(flag: Bool)
{
var angle: CGFloat = flag ? -0.01 : 0.01
angle += CGFloat(M_PI)
/*
transform旋轉(zhuǎn)動畫默認(rèn)是按照順時(shí)針旋轉(zhuǎn)的
但是旋轉(zhuǎn)時(shí)還有一個(gè)原則, 就近原則
*/
UIView.animateWithDuration(2.0) { () -> Void in
self.arrowImageView.transform = CGAffineTransformRotate(self.arrowImageView.transform, angle)
}
}
/// 顯示加載視圖
func startLoadingView()
{
// 0.隱藏提示視圖
tipView.hidden = true
if let _ = loadingImageView.layer.animationForKey("lnj")
{
// 如果已經(jīng)添加過動畫, 就直接返回
return
}
// 1.創(chuàng)建動畫
let anim = CABasicAnimation(keyPath: "transform.rotation")
// 2.設(shè)置動畫屬性
anim.toValue = 2 * M_PI
anim.duration = 5.0
anim.repeatCount = MAXFLOAT
// 3.將動畫添加到圖層上
loadingImageView.layer.addAnimation(anim, forKey: "lnj")
}
/// 隱藏加載視圖
func stopLoadingView()
{
// 0.顯示提示視圖
tipView.hidden = false
// 1.移除動畫
loadingImageView.layer.removeAllAnimations()
}
}
2.顯示提醒消息
/// 顯示刷新提醒
private func showRefreshStatus(count: Int)
{
// 1.設(shè)置提醒文本
tipLabel.text = (count == 0) ? "沒有更多數(shù)據(jù)" : "刷新到\(count)條數(shù)據(jù)"
tipLabel.hidden = false
// 2.執(zhí)行動畫
UIView.animateWithDuration(1.0, animations: { () -> Void in
// UIView.setAnimationRepeatAutoreverses(true)
self.tipLabel.transform = CGAffineTransformMakeTranslation(0, 44)
}) { (_) -> Void in
UIView.animateWithDuration(1.0, delay: 2.0, options: UIViewAnimationOptions(rawValue: 0), animations: { () -> Void in
self.tipLabel.transform = CGAffineTransformIdentity
}, completion: { (_) -> Void in
self.tipLabel.hidden = true
})
}
}
3.緩存行高
/// 緩存行高
private var rowHeightCaches = [String: CGFloat]()
// 返回行高
override func tableView(tableView: UITableView, heightForRowAtIndexPath indexPath: NSIndexPath) -> CGFloat {
let viewModel = statuses![indexPath.row]
let identifier = (viewModel.status.retweeted_status != nil) ? "forwardCell" : "homeCell"
// 1.從緩存中獲取行高
guard let height = rowHeightCaches[viewModel.status.idstr ?? "-1"] else
{
NJLog("計(jì)算行高")
// 緩存中沒有行高
// 2.計(jì)算行高
// 2.1獲取當(dāng)前行對應(yīng)的cell
let cell = tableView.dequeueReusableCellWithIdentifier(identifier) as! HomeTableViewCell
// 2.1緩存行高
let temp = cell.calculateRowHeight(viewModel)
rowHeightCaches[viewModel.status.idstr ?? "-1"] = temp
// 3.返回行高
return temp
}
// 緩存中有就直接返回緩存中的高度
return height
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// 釋放緩存數(shù)據(jù)
rowHeightCaches.removeAll()
}