Skip to content

Commit 6a16d11

Browse files
committed
Initial project
1 parent 3bc99e4 commit 6a16d11

File tree

6 files changed

+124
-1
lines changed

6 files changed

+124
-1
lines changed

PullToRefreshControl/.gitignore

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
.DS_Store
2+
/.build
3+
/Packages
4+
xcuserdata/
5+
DerivedData/
6+
.swiftpm/configuration/registries.json
7+
.swiftpm/xcode/package.xcworkspace/contents.xcworkspacedata
8+
.netrc
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
<?xml version="1.0" encoding="UTF-8"?>
2+
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
3+
<plist version="1.0">
4+
<dict>
5+
<key>IDEDidComputeMac32BitWarning</key>
6+
<true/>
7+
</dict>
8+
</plist>

PullToRefreshControl/Package.swift

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
// swift-tools-version: 5.9
2+
// The swift-tools-version declares the minimum version of Swift required to build this package.
3+
4+
import PackageDescription
5+
6+
let package = Package(
7+
name: "PullToRefreshControl",
8+
products: [
9+
// Products define the executables and libraries a package produces, making them visible to other packages.
10+
.library(
11+
name: "PullToRefreshControl",
12+
targets: ["PullToRefreshControl"]),
13+
],
14+
targets: [
15+
// Targets are the basic building blocks of a package, defining a module or a test suite.
16+
// Targets can depend on other targets in this package and products from dependencies.
17+
.target(
18+
name: "PullToRefreshControl"),
19+
.testTarget(
20+
name: "PullToRefreshControlTests",
21+
dependencies: ["PullToRefreshControl"]),
22+
]
23+
)
Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
//
2+
// PullToRefreshControl.swift
3+
// PullToRefreshControl
4+
//
5+
// Created by Blazej SLEBODA on 14/01/2024.
6+
//
7+
8+
import UIKit
9+
10+
public class PullToRefreshControl: UIRefreshControl {
11+
public override init(frame: CGRect) {
12+
super.init(frame: frame)
13+
commonInit()
14+
}
15+
public required init?(coder: NSCoder) {
16+
super.init(coder: coder)
17+
commonInit()
18+
}
19+
private func commonInit() {
20+
NotificationCenter.default.addObserver(forName: UIApplication.didBecomeActiveNotification, object: nil, queue: .main) { [weak self] _ in
21+
self?.cancelOrRestartRefreshingIfNeeded()
22+
}
23+
}
24+
public func pullToRefresh() {
25+
guard let superview = superview as? UITableView else {
26+
return
27+
}
28+
superview.contentOffset = .init(x: superview.contentOffset.x, y: -frame.height)
29+
beginRefreshing()
30+
sendActions(for: .valueChanged)
31+
}
32+
public func cancelOrRestartRefreshingIfNeeded() {
33+
cancelIncompletePullToRefreshIfNeeded()
34+
restartBeginRefreshingIfNeeded()
35+
}
36+
private func restartBeginRefreshingIfNeeded() {
37+
guard
38+
isRefreshing,
39+
let superview = superview as? UITableView
40+
else { return }
41+
let oldValueContentOffset = superview.contentOffset
42+
UIView.performWithoutAnimation {
43+
endRefreshing()
44+
}
45+
DispatchQueue.main.async {
46+
superview.contentOffset = oldValueContentOffset
47+
self.beginRefreshing()
48+
}
49+
}
50+
private func cancelIncompletePullToRefreshIfNeeded() {
51+
guard
52+
!isRefreshing,
53+
let superview = superview as? UITableView,
54+
superview.contentOffset != .zero
55+
else { return }
56+
UIView.performWithoutAnimation { [weak self] in
57+
self?.endRefreshing()
58+
}
59+
}
60+
}
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
import XCTest
2+
@testable import PullToRefreshControl
3+
4+
final class PullToRefreshControlTests: XCTestCase {
5+
func testExample() throws {
6+
// XCTest Documentation
7+
// https://developer.apple.com/documentation/xctest
8+
9+
// Defining Test Cases and Test Methods
10+
// https://developer.apple.com/documentation/xctest/defining_test_cases_and_test_methods
11+
}
12+
}

README.md

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,14 @@
11
# PullToRefreshControl
2-
UIRefreshControl with programatic pull to refresh and fixed paused animations and inclomplete pull to refresh
2+
3+
"PullToRefreshControl" is a custom subclass of UIRefreshControl, designed to enhance the functionality of the standard pull-to-refresh action in iOS applications. This control is specifically tailored for use with UITableView, offering a programmable approach to initiate the refresh action and addressing a common issue where the refresh animation pauses or fails to resume correctly.
4+
5+
Key Features
6+
7+
1. Programmatic Refresh Triggering:
8+
The control introduces a method, pullToRefresh(), allowing developers to initiate the pull-to-refresh action programmatically. This is particularly useful for scenarios where the refresh needs to be triggered without user interaction, such as during the initial loading of the table view.
9+
2. Handling App State Transitions:
10+
It automatically manages the refresh control's state during various app state transitions. This includes scenarios where the app returns from the background, or when the user navigates back to the view controller containing the UITableView.
11+
3. Seamless Animation Continuity:
12+
The cancelOrRestartRefreshingIfNeeded() method ensures that the refresh animation continues seamlessly. It addresses the common issue where the animation gets paused or stuck, especially after the app transitions from the background or when returning from another view controller.
13+
4. Improved User Experience:
14+
By fixing the interrupted animation issue, this control provides a smoother and more consistent user experience. It maintains the visual feedback that users expect when they initiate a refresh action.

0 commit comments

Comments
 (0)