GTMRefresh github
===================
GTMRefresh
用Swift重寫的MJRefresh
Introduction
- 自定義方便, Demo里面有國內(nèi)主流App的下拉效果的模仿
- 代碼簡潔焊唬,總代碼量不超過1000行
- 支持國際化
- 支持: UITableView, UICollectionView, UIScrollView, UIWebView
Demo
直接下載代碼皆警,里面Demo里面有各種效果的自定義效果(因為時間比較緊,demo代碼可能不夠漂亮)
Demo模仿的下拉效果
- YahooWeather
- Curve Mask
- Youku
- TaoBao
- QQ Video
- DianPing
Installation
Cocoapods
Install Cocoapods if need be.
$ gem install cocoapods
Add GTMRefresh
in your Podfile
.
use_frameworks!
pod 'GTMRefresh'
Then, run the following command.
$ pod install
Manual
Copy GTMRefresh
folder to your project. That's it.
Note: Make sure that all files in GTMRefresh
included in Compile Sources in Build Phases.
版本
Vesrion 0.0.1
This version requires Xcode 8.0 and Swift 3.
使用幫助
Firstly, import GTMRefresh
.
import GTMRefresh
使用默認的下拉和上拉效果
self.tableView.gtm_addRefreshHeaderView {
[weak self] in
print("excute refreshBlock")
self.refresh()
}
self.tableView.gtm_addLoadMoreFooterView {
[weak self] in
print("excute loadMoreBlock")
self.loadMore()
}
代碼觸發(fā)刷新
self.tableView.triggerRefreshing()
自定義下拉刷新效果
約定
- 必須繼承 GTMRefreshHeader
- 必須實現(xiàn) SubGTMRefreshHeaderProtocol
SubGTMRefreshHeaderProtocol
public protocol SubGTMRefreshHeaderProtocol {
/// 狀態(tài)變成.idle
func toNormalState()
/// 狀態(tài)變成.refreshing
func toRefreshingState()
/// 狀態(tài)變成.pulling
func toPullingState()
/// 狀態(tài)變成.willRefresh
func toWillRefreshState()
/// 下拉高度/觸發(fā)高度 值改變
func changePullingPercent(percent: CGFloat)
/// 開始結束動畫前執(zhí)行
func willBeginEndRefershing(isSuccess: Bool)
/// 結束動畫完成后執(zhí)行
func willCompleteEndRefershing()
/// 控件的高度
///
/// - Returns: 控件的高度
func contentHeight() -> CGFloat
}
特殊效果的實現(xiàn)
- 當觸發(fā)刷新的高度和控件高度不一樣時重寫willRefresHeight(),如Demo里的:Curve Mask
/// 即將觸發(fā)刷新的高度(特殊的控件需要重寫該方法把篓,返回不同的數(shù)值)
///
/// - Returns: 觸發(fā)刷新的高度
open func willRefresHeight() -> CGFloat {
return self.mj_h // 默認使用控件高度
}
- 當Loadding動畫顯示區(qū)域的高度和控件高度不一樣時重寫refreshingHoldHeight()单旁,如Demo里的:QQ
/// Loadding動畫顯示區(qū)域的高度(特殊的控件需要重寫該方法,返回不同的數(shù)值)
///
/// - Returns: Loadding動畫顯示區(qū)域的高度
open func refreshingHoldHeight() -> CGFloat {
return self.mj_h // 默認使用控件高度
}
Example
//
// TaoBaoRefreshHeader.swift
// PullToRefreshKit
//
// Created by luoyang on 10/12/16.
// Copyright ? 2016年 luoyang. All rights reserved.
//
import UIKit
import GTMRefresh
class TaoBaoRefreshHeader: GTMRefreshHeader, SubGTMRefreshHeaderProtocol {
fileprivate let circleLayer = CAShapeLayer()
fileprivate let arrowLayer = CAShapeLayer()
let imageView = UIImageView(frame: CGRect(x: 0, y: 0, width: 230, height: 35))
fileprivate let textLabel = UILabel()
fileprivate let strokeColor = UIColor(red: 135.0/255.0, green: 136.0/255.0, blue: 137.0/255.0, alpha: 1.0)
override init(frame: CGRect) {
super.init(frame: frame)
setUpCircleLayer()
setUpArrowLayer()
textLabel.textAlignment = .center
textLabel.textColor = UIColor.lightGray
textLabel.font = UIFont.systemFont(ofSize: 14)
textLabel.text = "下拉即可刷新..."
imageView.image = UIImage(named: "taobaoLogo")
self.contentView.addSubview(imageView)
self.contentView.addSubview(textLabel)
}
func setUpArrowLayer(){
let bezierPath = UIBezierPath()
bezierPath.move(to: CGPoint(x: 20, y: 15))
bezierPath.addLine(to: CGPoint(x: 20, y: 25))
bezierPath.addLine(to: CGPoint(x: 25,y: 20))
bezierPath.move(to: CGPoint(x: 20, y: 25))
bezierPath.addLine(to: CGPoint(x: 15, y: 20))
self.arrowLayer.path = bezierPath.cgPath
self.arrowLayer.strokeColor = UIColor.lightGray.cgColor
self.arrowLayer.fillColor = UIColor.clear.cgColor
self.arrowLayer.lineWidth = 1.0
self.arrowLayer.lineCap = kCALineCapRound
self.arrowLayer.bounds = CGRect(x: 0, y: 0,width: 40, height: 40)
self.arrowLayer.anchorPoint = CGPoint(x: 0.5, y: 0.5)
self.layer.addSublayer(self.arrowLayer)
}
func setUpCircleLayer(){
let bezierPath = UIBezierPath(arcCenter: CGPoint(x: 20, y: 20),
radius: 12.0,
startAngle:CGFloat(-M_PI/2),
endAngle: CGFloat(M_PI_2 * 3),
clockwise: true)
self.circleLayer.path = bezierPath.cgPath
self.circleLayer.strokeColor = UIColor.lightGray.cgColor
self.circleLayer.fillColor = UIColor.clear.cgColor
self.circleLayer.strokeStart = 0.05
self.circleLayer.strokeEnd = 0.05
self.circleLayer.lineWidth = 1.0
self.circleLayer.lineCap = kCALineCapRound
self.circleLayer.bounds = CGRect(x: 0, y: 0,width: 40, height: 40)
self.circleLayer.anchorPoint = CGPoint(x: 0.5, y: 0.5)
self.layer.addSublayer(self.circleLayer)
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
override func layoutSubviews() {
super.layoutSubviews()
textLabel.frame = CGRect(x: 0,y: 0,width: 120, height: 40)
//放置Views和Layer
imageView.center = CGPoint(x: frame.width/2, y: frame.height - 60 - 18)
textLabel.center = CGPoint(x: frame.width/2 + 20, y: frame.height - 30)
self.arrowLayer.position = CGPoint(x: frame.width/2 - 60, y: frame.height - 30)
self.circleLayer.position = CGPoint(x: frame.width/2 - 60, y: frame.height - 30)
}
func toNormalState() {}
func toRefreshingState() {
self.circleLayer.strokeEnd = 0.95
let rotateAnimation = CABasicAnimation(keyPath: "transform.rotation.z")
rotateAnimation.toValue = NSNumber(value: M_PI * 2.0 as Double)
rotateAnimation.duration = 0.6
rotateAnimation.isCumulative = true
rotateAnimation.repeatCount = 10000000
self.circleLayer.add(rotateAnimation, forKey: "rotate")
self.arrowLayer.isHidden = true
textLabel.text = "刷新中..."
}
func toPullingState() {}
func toWillRefreshState() {}
func changePullingPercent(percent: CGFloat) {
let adjustPercent = max(min(1.0, percent),0.0)
if adjustPercent == 1.0{
textLabel.text = "釋放即可刷新..."
}else{
textLabel.text = "下拉即可刷新..."
}
self.circleLayer.strokeEnd = 0.05 + 0.9 * adjustPercent
}
func willBeginEndRefershing(isSuccess: Bool) {}
func willCompleteEndRefershing() {
transitionWithOutAnimation {
self.circleLayer.strokeEnd = 0.05
};
self.circleLayer.removeAllAnimations()
self.arrowLayer.isHidden = false
textLabel.text = "下拉即可刷新"
}
func contentHeight()->CGFloat{
return 60
}
/// MARK: Private
func transitionWithOutAnimation(_ clousre:()->()){
CATransaction.begin()
CATransaction.setDisableActions(true)
clousre()
CATransaction.commit()
}
}
自定義控件的使用
self.tableView.gtm_addRefreshHeaderView(refreshHeader: CustomRefreshHeader()) {
[weak self] in
print("excute refreshBlock")
self.refresh()
}
自定義上拉加載效果
約定
- 必須繼承 GTMLoadMoreFooter
- 必須實現(xiàn) SubGTMLoadMoreFooterProtocol
SubGTMLoadMoreFooterProtocol
public protocol SubGTMLoadMoreFooterProtocol {
func toNormalState()
func toNoMoreDataState()
func toWillRefreshState()
func toRefreshingState()
/// 控件的高度(自定義控件通過該方法設置自定義高度)
///
/// - Returns: 控件的高度
func contentHeith() -> CGFloat
}