Skip to content

Commit 4b5ca29

Browse files
refresh control flickering fix (#8172)
Co-authored-by: Georgy Steshin <gosha212@gmail.com>
1 parent 3ff3f6b commit 4b5ca29

File tree

1 file changed

+91
-0
lines changed

1 file changed

+91
-0
lines changed

ios/RNNRefreshControll.m

Lines changed: 91 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,91 @@
1+
/**
2+
* Fix for UIRefreshControl spinner flicker with large titles.
3+
* iOS UIKit internally toggles hidden state during layout changes,
4+
* causing the spinner to flicker. This swizzles setHidden to block
5+
* visibility changes while the control is actively refreshing.
6+
*/
7+
8+
#import <UIKit/UIKit.h>
9+
#import <objc/runtime.h>
10+
11+
static char kRNNIsEndingRefreshKey;
12+
13+
@implementation UIRefreshControl (RNNStable)
14+
15+
+ (void)load {
16+
static dispatch_once_t onceToken;
17+
dispatch_once(&onceToken, ^{
18+
Class class = [self class];
19+
20+
// Swizzle setHidden
21+
SEL originalSelector = @selector(setHidden:);
22+
SEL swizzledSelector = @selector(rnn_setHidden:);
23+
24+
Method originalMethod = class_getInstanceMethod(class, originalSelector);
25+
Method swizzledMethod = class_getInstanceMethod(class, swizzledSelector);
26+
27+
BOOL didAddMethod = class_addMethod(class,
28+
originalSelector,
29+
method_getImplementation(swizzledMethod),
30+
method_getTypeEncoding(swizzledMethod));
31+
32+
if (didAddMethod) {
33+
class_replaceMethod(class,
34+
swizzledSelector,
35+
method_getImplementation(originalMethod),
36+
method_getTypeEncoding(originalMethod));
37+
} else {
38+
method_exchangeImplementations(originalMethod, swizzledMethod);
39+
}
40+
41+
// Swizzle endRefreshing
42+
SEL originalEndSelector = @selector(endRefreshing);
43+
SEL swizzledEndSelector = @selector(rnn_endRefreshing);
44+
45+
Method originalEndMethod = class_getInstanceMethod(class, originalEndSelector);
46+
Method swizzledEndMethod = class_getInstanceMethod(class, swizzledEndSelector);
47+
48+
didAddMethod = class_addMethod(class,
49+
originalEndSelector,
50+
method_getImplementation(originalEndMethod),
51+
method_getTypeEncoding(originalEndMethod));
52+
53+
if (didAddMethod) {
54+
class_replaceMethod(class,
55+
swizzledEndSelector,
56+
method_getImplementation(originalEndMethod),
57+
method_getTypeEncoding(originalEndMethod));
58+
} else {
59+
method_exchangeImplementations(originalEndMethod, swizzledEndMethod);
60+
}
61+
});
62+
}
63+
64+
- (BOOL)rnn_isEndingRefresh {
65+
return [objc_getAssociatedObject(self, &kRNNIsEndingRefreshKey) boolValue];
66+
}
67+
68+
- (void)rnn_setIsEndingRefresh:(BOOL)value {
69+
objc_setAssociatedObject(self, &kRNNIsEndingRefreshKey, @(value), OBJC_ASSOCIATION_RETAIN_NONATOMIC);
70+
}
71+
72+
- (void)rnn_endRefreshing {
73+
[self rnn_setIsEndingRefresh:YES];
74+
[self rnn_endRefreshing];
75+
[self rnn_setIsEndingRefresh:NO];
76+
}
77+
78+
- (void)rnn_setHidden:(BOOL)hidden {
79+
if ([self rnn_isEndingRefresh]) {
80+
[self rnn_setHidden:hidden];
81+
return;
82+
}
83+
84+
if (self.isRefreshing) {
85+
return;
86+
}
87+
88+
[self rnn_setHidden:hidden];
89+
}
90+
91+
@end

0 commit comments

Comments
 (0)