Skip to content

wgl0419/GTMRefresh

 
 

Repository files navigation


GTMRefresh

GTMRefresh 用Swift重写的MJRefresh

Introduction

  • 自定义方便, Demo里面有国内主流App的下拉效果的模仿
  • 代码简洁,总代码量不超过1000行
  • 支持国际化
  • 支持: UITableView, UICollectionView, UIScrollView, UIWebView

Demo

直接下载代码,里面Demo里面有各种效果的自定义效果(因为时间比较紧,demo代码可能不够漂亮)

alt tag alt tag alt tag alt tag alt tag

Demo模仿的下拉效果

  • YahooWeather
  • Curve Mask
  • Youku
  • TaoBao
  • QQ Video
  • DianPing
  • QQ

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 1.0.0

This version requires Xcode 8.0 and Swift 3.

使用帮助

Firstly, import GTMRefresh.

import GTMRefresh

使用默认的下拉和上拉效果

    self.tableView.gtm_addRefreshHeaderView {
        [unowned self] in
        print("excute refreshBlock")
        self.refresh()
    }

    self.tableView.gtm_addLoadMoreFooterView {
        [unowned self] in
        print("excute loadMoreBlock")
        self.loadMore()
    }

自定义下拉和上拉文本

    self.tableView?.gtm_addRefreshHeaderView {
        [unowned self] in
        print("excute refreshBlock")
        self.refresh()
    }.setupHeaderText(pullDownToRefreshText: "下拉试试看",
                    releaseToRefreshText: "松开现神奇",
                    refreshSuccessText: "成功",
                    refreshFailureText: "失败",
                    refreshingText: "刷新...")

    self.tableView?.gtm_addLoadMoreFooterView {
        [unowned self] in
        print("excute loadMoreBlock")
        self.loadMore()
    }.setupFooterText(pullUpToRefreshText: "用力往上拉",
                    loaddingText: "努力加载中...",
                    noMoreDataText: "没有更多了",
                    releaseLoadMoreText: "轻轻一松,开始加载")

代码触发刷新

    self.tableView.triggerRefreshing()

自定义下拉刷新效果

约定

  • 必须继承 GTMRefreshHeader
  • 必须实现 SubGTMRefreshHeaderProtocol

SubGTMRefreshHeaderProtocol

public protocol SubGTMRefreshHeaderProtocol {
    /// 状态变成.idle
    func toNormalState()
    /// 状态变成.refreshing
    func toRefreshingState()
    /// 状态变成.pulling
    func toPullingState()
    /// 状态变成.willRefresh
    func toWillRefreshState()
    /// 下拉高度/触发高度 值改变
    func changePullingPercent(percent: CGFloat)
    /// 开始结束动画前执行
    func willBeginEndRefershing(isSuccess: Bool)
    /// 结束动画完成后执行
    func willCompleteEndRefershing()

    /// 控件的高度
    ///
    /// - Returns: 控件的高度
    func contentHeight() -> CGFloat
}

特殊效果的实现

  • 当触发刷新的高度和控件高度不一样时重写willRefresHeight(),如Demo里的:Curve Mask
    /// 即将触发刷新的高度(特殊的控件需要重写该方法,返回不同的数值)
    ///
    /// - Returns: 触发刷新的高度
    open func willRefresHeight() -> CGFloat {
        return self.mj_h // 默认使用控件高度
    }
  • 当Loadding动画显示区域的高度和控件高度不一样时重写refreshingHoldHeight(),如Demo里的:QQ
    /// Loadding动画显示区域的高度(特殊的控件需要重写该方法,返回不同的数值)
    ///
    /// - Returns: Loadding动画显示区域的高度
    open func refreshingHoldHeight() -> CGFloat {
        return self.mj_h // 默认使用控件高度
    }

Example

//
//  TaoBaoRefreshHeader.swift
//  PullToRefreshKit
//
//  Created by luoyang on 2016/12/8.
//  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()) {
        [unowned self] in
        print("excute refreshBlock")
        self.refresh()
    }

自定义上拉加载效果

约定

  • 必须继承 GTMLoadMoreFooter
  • 必须实现 SubGTMLoadMoreFooterProtocol

SubGTMLoadMoreFooterProtocol

public protocol SubGTMLoadMoreFooterProtocol {
    func toNormalState()
    func toNoMoreDataState()
    func toWillRefreshState()
    func toRefreshingState()

    /// 控件的高度(自定义控件通过该方法设置自定义高度)
    ///
    /// - Returns: 控件的高度
    func contentHeith() -> CGFloat
}

#参与开源 欢迎提交 issue 和 PR,大门永远向所有人敞开。

#开源协议 本项目遵循 MIT 协议开源,具体请查看根目录下的 LICENSE 文件。

About

No description, website, or topics provided.

Resources

License

Stars

Watchers

Forks

Packages

No packages published

Languages

  • Swift 99.3%
  • Ruby 0.7%