Latest 2.2.2
License MIT
Platforms ios 8.0, requires ARC
Dependencies ZVActivityIndicatorView

ZVRefreshing is a pure-swift and wieldy refresh component.



  • iOS 8.0+
Swift Version Repo Version
Swift 5.0 > 2.2.0
Swift 4.2 < 2.1.3



CocoaPods is a dependency manager for Swift and Objective-C Cocoa projects.

You can install Cocoapod with the following command

$ sudo gem install cocoapods

To integrate ZVRefreshing into your project using CocoaPods, specify it into your Podfile

source ''
platform :ios, '8.0'

target 'TargetName' do
    pod 'ZVRefreshing' ~> '2.0.0'

Then,install your dependencies with CocoaPods.

$ pod install


Carthage is intended to be the simplest way to add frameworks to your application.

You can install Carthage with Homebrew using following command:

$ brew update
$ brew install carthage

To integrate ZVRefreshing into your project using Carthage, specify it into your Cartfile

github "zevwings/ZVRefreshing" ~> 0.0.1

Then,build the framework with Carthage
using carthage update and drag ZVRefreshing.framework into your project.


The framework is under the Carthage/Build, and you should drag it into Target -> Genral -> Embedded Binaries


Download this project, And drag ZRefreshing.xcodeproj into your own project.

In your target’s General tab, click the ’+’ button under Embedded Binaries

Select the ZRefreshing.framework to Add to your platform.



You can use online demo on Appetize

Genaral Usage

When you need add a refresh widget, you can use import ZVRefreshing


There is three ways to initialize this widget.

  • Target-Action
let header = ZVRefreshNormalHeader(target: NSObject, action: Selector)
self.tableView.header = header
  • Block
let header = ZVRefreshNormalHeader(refreshHandler: { [weak self] in 
    // your codes    
self.tableView.header = header
  • None-parameters
let header = RefreshHeader()
self.tableView.header = header

if you initialize the widget by none-parameters way, you can add refresh handler block or target-action with following code:

  1. add a refresh handler
// add refresh handler
header?.refreshHandler = {
    // your codes            
  1. add a Target-Action
// add refresh target-action
header?.addTarget(Any?, action: Selector)
  1. add a Target-Action-UIControlEvents.valueChanged
// The ZVRefreshComponent extend from UIControl, When isRefreshing properties changed will send a UIControlEvents.valueChanged event.
header?.addTarget(Any, action: Selector, for: .valueChanged)


The functions is same for header and footer.

  1. beginRefreshing()

The widget begin enter into refreshing status.

  1. endRefreshing()

The widge begin enter into idle status.

  1. setTitle(_:forState:)
    To custom the title for widget, this function in ZVRefreshStateHeader.
header.setTitle("pull to refresh...", forState: .idle)
header.setTitle("release to refresh...", forState: .pulling)
header.setTitle("loading...", forState: .refreshing)


 footer.setTitle("pull to refresh...", forState: .idle)
 footer.setTitle("release to refresh...", forState: .pulling)
 footer.setTitle("loading...", forState: .refreshing)
 footer.setTitle("no more data", forState: .noMoreData)
  1. setImages(_:forState:)
    To custom the images for widget, this function in ZVRefreshAnimationHeader, you can use it as following code, also you can extend a subclass, like Example
self.setImages(idleImages, forState: .idle)
self.setImages(refreshingImages, forState: .pulling)
self.setImages(refreshingImages, forState: .refreshing)



  1. lastUpdatedTimeKey
    To storage the last time using this widget, if it dose not set, all your widget will shared a key com.zevwings.refreshing.lastUpdateTime
header.lastUpdatedTimeKey = "custom last updated key"
  1. ignoredScrollViewContentInsetTop

when your table set contentInset property, you should set it, for example:

self.tableView.contentInset = UIEdgeInsets(top: 30, left: 0, bottom:0, right: 0)
header.ignoredScrollViewContentInsetTop = 30
  1. lastUpdatedTimeLabel

To custom the UILabel properties for lastUpdatedTimeLabel, for example:

// hide the lastUpdatedTimeLabel
header.lastUpdatedTimeLabel.isHidden = true


// set the font for lastUpdatedTimeLabel
header.lastUpdatedTimeLabel.font = .systemFont(ofSize: 16.0)
  1. lastUpdatedTimeLabelText

To custom the format for showing last time.

header.lastUpdatedTimeLabelText = { date in

    if let d = date {
        let formatter = DateFormatter()
        formatter.dateFormat = "yyyy-MM-dd HH:mm:ss"
        return "Last updated:(formatter.string(from: d))"
    return "There is no record"


  1. isAutomaticallyHidden
    To set the automatically hidden for widget, default is true
footer.isAutomaticallyHidden = false
  1. ignoredScrollViewContentInsetBottom
    when your table set contentInset property, you should set it, for example:
self.tableView.contentInset = UIEdgeInsets(top:0, left: 0, bottom:30, right: 0)
footer.ignoredScrollViewContentInsetBottom = 30
  1. isAutomaticallyRefresh
    To set the automatically refresh for widget, default is true, this property in ZVRefreshAutoFooter
footer.isAutomaticallyRefresh = false


The following properties is same for header and footer.

  1. labelInsetLeft
    To set the empty width between activityIndicator an label.
header.labelInsetLeft = 32.0
  1. activityIndicator
    To custom the properties for activityIndicator, the properties @see ZActivityIndicatorView

  2. tintColor
    To custom the color for all sub-widget.
header.tintColor = .black
  1. stateLabel
    To custom the UILabel properties for stateLabel, for example:
// hide the stateLabel
header.stateLabel.isHidden = true


// set the font for stateLabel
header.stateLabel.font = .systemFont(ofSize: 16.0)
  1. animationView

To custom the UIImageView properties for stateLabel, for example:

Custom Usage

You can extend ZVRefreshComponent or it’s sub-class to custom your own refresh widget.
like Example.


  1. state

To custom you needed when refresh state changed.

open var state: ZVRefreshComponent.State
  1. pullingPercent

To custom you needed when widget position changed.

open var pullingPercent: CGFloat
  1. tintColor

To custom you own widget color.

open override var tintColor: UIColor!


  1. prepare

To define your own controls, call at init(frame: CGRect).

open func prepare() {}
  1. placeSubViews

To set your own constrols size and position, call at layoutSubviews().

open func placeSubViews() {}
  1. scrollViewContentOffsetDidChanged

To observe the UIScrollView.contentOffset, call at UIScrollView.contentOffset value changed.

open func scrollViewContentOffsetDidChanged(_ change: [NSKeyValueChangeKey: Any]?) {}
  1. scrollViewContentSizeDidChanged

To observe the UIScrollView.contentSize, call at UIScrollView.contentSize value changed.

open func scrollViewContentSizeDidChanged(_ change: [NSKeyValueChangeKey: Any]?) {}
  1. scrollViewPanStateDidChanged

To observe the UIScrollView.panGestureRecognizer.state, call at UIScrollView.panGestureRecognizer.state value changed.

open func scrollViewPanStateDidChanged(_ change: [NSKeyValueChangeKey: Any]?) {}

Rx Support

If you want use RxSwift, refer to ZVRefreshing+Rx.swift.

Then, you can use the follow codes to start a refresh action.

    .asDriver(onErrorJustReturn: false)
    .disposed(by: disposeBag)

Or, you can use this codes to observe the refreshing state.

    .subscribe(onNext: { isRefreshing in
        print("onNext isRefreshing : (isRefreshing)")
    }, onError: { err in
        print("err : (err)")
    }, onCompleted: {
    }, onDisposed: {
    }).disposed(by: disposeBag)

More Usage

You can refer to the Example for more usage.

Issue or Suggestion

You can issue me on GitHub or send a email[email protected].
If you have a good idea, tell me.


ZVRefreshing distributed under the terms and conditions of the MIT License.

Latest podspec

    "name": "ZVRefreshing",
    "version": "2.2.2",
    "summary": "A pure-swift and wieldy refresh component.",
    "description": "ZRefreshing is a pure-swift and wieldy refresh component.",
    "homepage": "",
    "license": "MIT",
    "authors": {
        "zevwings": "[email protected]"
    "platforms": {
        "ios": "8.0"
    "source": {
        "git": "",
        "tag": "2.2.2"
    "resources": "ZVRefreshing/Resource/*",
    "source_files": [
    "requires_arc": true,
    "dependencies": {
        "ZVActivityIndicatorView": []

Pin It on Pinterest

Share This