Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

修复UICollectionView使用performBatchUpdates时的MJRefreshAutoFooter/MJRefreshBackFooter的问题 #1554

Merged
merged 8 commits into from
Nov 19, 2021
14 changes: 12 additions & 2 deletions MJRefresh/Base/MJRefreshAutoFooter.m
Original file line number Diff line number Diff line change
Expand Up @@ -63,9 +63,19 @@ - (void)prepare
- (void)scrollViewContentSizeDidChange:(NSDictionary *)change
{
[super scrollViewContentSizeDidChange:change];

CGFloat contentHeight = 0;
NSValue *value = [change objectForKey:NSKeyValueChangeNewKey];
if ([value isKindOfClass:NSValue.class]) {
contentHeight = [value CGSizeValue].height;
}
if (contentHeight == 0) {
contentHeight = self.scrollView.mj_contentH;
}
// 设置位置
self.mj_y = self.scrollView.mj_contentH + self.ignoredScrollViewContentInsetBottom;
CGFloat y = contentHeight + self.ignoredScrollViewContentInsetBottom;
if (self.mj_y != y) {
self.mj_y = y;
}
}

- (void)scrollViewContentOffsetDidChange:(NSDictionary *)change
Expand Down
16 changes: 13 additions & 3 deletions MJRefresh/Base/MJRefreshBackFooter.m
Original file line number Diff line number Diff line change
Expand Up @@ -71,13 +71,23 @@ - (void)scrollViewContentOffsetDidChange:(NSDictionary *)change
- (void)scrollViewContentSizeDidChange:(NSDictionary *)change
{
[super scrollViewContentSizeDidChange:change];

CGFloat contentHeight = 0;
NSValue *value = [change objectForKey:NSKeyValueChangeNewKey];
if ([value isKindOfClass:NSValue.class]) {
contentHeight = [value CGSizeValue].height;
}
if (contentHeight == 0) {
contentHeight = self.scrollView.mj_contentH;
}
// 内容的高度
CGFloat contentHeight = self.scrollView.mj_contentH + self.ignoredScrollViewContentInsetBottom;
contentHeight = contentHeight + self.ignoredScrollViewContentInsetBottom;
// 表格的高度
CGFloat scrollHeight = self.scrollView.mj_h - self.scrollViewOriginalInset.top - self.scrollViewOriginalInset.bottom + self.ignoredScrollViewContentInsetBottom;
// 设置位置和尺寸
self.mj_y = MAX(contentHeight, scrollHeight);
CGFloat y = MAX(contentHeight, scrollHeight);
if (self.mj_y != y) {
self.mj_y = y;
}
}

- (void)setState:(MJRefreshState)state
Expand Down
26 changes: 26 additions & 0 deletions MJRefresh/MJRefreshConst.h
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
// 代码地址: https://github.com/CoderMJLee/MJRefresh
#import <UIKit/UIKit.h>
#import <objc/message.h>
#import <objc/runtime.h>

// 弱引用
#define MJWeakSelf __weak typeof(self) weakSelf = self;
Expand Down Expand Up @@ -79,3 +80,28 @@ dispatch_async(dispatch_get_main_queue(), ^{ \
typeof(weakSelf) self = weakSelf; \
{x} \
});

// runtime
CG_INLINE BOOL
MJRefreshExchangeImplementationsInTwoClasses(Class _fromClass, SEL _originSelector, Class _toClass, SEL _newSelector) {
if (!_fromClass || !_toClass) {
return NO;
}

Method oriMethod = class_getInstanceMethod(_fromClass, _originSelector);
Method newMethod = class_getInstanceMethod(_toClass, _newSelector);
if (!newMethod) {
return NO;
}

BOOL isAddedMethod = class_addMethod(_fromClass, _originSelector, method_getImplementation(newMethod), method_getTypeEncoding(newMethod));
if (isAddedMethod) {
// 如果 class_addMethod 成功了,说明之前 fromClass 里并不存在 originSelector,所以要用一个空的方法代替它,以避免 class_replaceMethod 后,后续 toClass 的这个方法被调用时可能会 crash
IMP oriMethodIMP = method_getImplementation(oriMethod) ?: imp_implementationWithBlock(^(id selfObject) {});
const char *oriMethodTypeEncoding = method_getTypeEncoding(oriMethod) ?: "v@:";
class_replaceMethod(_toClass, _newSelector, oriMethodIMP, oriMethodTypeEncoding);
} else {
method_exchangeImplementations(oriMethod, newMethod);
}
return YES;
}
17 changes: 17 additions & 0 deletions MJRefresh/UICollectionViewLayout+MJRefresh.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
//
// UICollectionViewLayout+MJRefresh.h
// MJRefreshExample
//
// Created by jiasong on 2021/11/15.
// Copyright © 2021 小码哥. All rights reserved.
//

#import <UIKit/UIKit.h>

NS_ASSUME_NONNULL_BEGIN

@interface UICollectionViewLayout (MJRefresh)

@end

NS_ASSUME_NONNULL_END
36 changes: 36 additions & 0 deletions MJRefresh/UICollectionViewLayout+MJRefresh.m
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
//
// UICollectionViewLayout+MJRefresh.m
// MJRefreshExample
//
// Created by jiasong on 2021/11/15.
// Copyright © 2021 小码哥. All rights reserved.
//

#import "UICollectionViewLayout+MJRefresh.h"
#import "MJRefreshConst.h"
#import "MJRefreshFooter.h"

@implementation UICollectionViewLayout (MJRefresh)

+ (void)load {
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
MJRefreshExchangeImplementationsInTwoClasses([self class], @selector(finalizeCollectionViewUpdates), [self class], @selector(mj_finalizeCollectionViewUpdates));
});
}

- (void)mj_finalizeCollectionViewUpdates {
jiasongs marked this conversation as resolved.
Show resolved Hide resolved
__kindof MJRefreshFooter *footer = self.collectionView.mj_footer;
if (footer != nil && footer.isRefreshing) {
NSDictionary *changed = @{
NSKeyValueChangeNewKey: [NSValue valueWithCGSize:self.collectionViewContentSize],
NSKeyValueChangeOldKey: [NSValue valueWithCGSize:self.collectionView.contentSize],
};
[CATransaction begin];
[CATransaction setDisableActions:YES];
[footer scrollViewContentSizeDidChange:changed];
[CATransaction commit];
}
jiasongs marked this conversation as resolved.
Show resolved Hide resolved
}

@end
20 changes: 16 additions & 4 deletions MJRefreshExample.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -101,6 +101,10 @@
2DB2EA281BECBE6700D58F6A /* UIScrollView+MJRefresh.m in Sources */ = {isa = PBXBuildFile; fileRef = 2DB2EA141BECBE6700D58F6A /* UIScrollView+MJRefresh.m */; };
2DB2EA291BECBE6700D58F6A /* UIView+MJExtension.m in Sources */ = {isa = PBXBuildFile; fileRef = 2DB2EA161BECBE6700D58F6A /* UIView+MJExtension.m */; };
6B8FB1A9250E610D00AF64B7 /* MJHorizontalCollectionViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 6B8FB1A8250E610D00AF64B7 /* MJHorizontalCollectionViewController.m */; };
7A698CD2274232A00028A4DD /* UICollectionViewLayout+MJRefresh.h in Headers */ = {isa = PBXBuildFile; fileRef = 7A698CD0274232A00028A4DD /* UICollectionViewLayout+MJRefresh.h */; };
7A698CD3274232A00028A4DD /* UICollectionViewLayout+MJRefresh.m in Sources */ = {isa = PBXBuildFile; fileRef = 7A698CD1274232A00028A4DD /* UICollectionViewLayout+MJRefresh.m */; };
7A698CD4274232A00028A4DD /* UICollectionViewLayout+MJRefresh.m in Sources */ = {isa = PBXBuildFile; fileRef = 7A698CD1274232A00028A4DD /* UICollectionViewLayout+MJRefresh.m */; };
jiasongs marked this conversation as resolved.
Show resolved Hide resolved
7A698CD5274232A00028A4DD /* UICollectionViewLayout+MJRefresh.m in Sources */ = {isa = PBXBuildFile; fileRef = 7A698CD1274232A00028A4DD /* UICollectionViewLayout+MJRefresh.m */; };
84FC857E228037CE001C6728 /* MJRefreshConfig.m in Sources */ = {isa = PBXBuildFile; fileRef = 01A2CE0B21ACE01500BEE365 /* MJRefreshConfig.m */; };
88E3200B24839ABA00069FA7 /* MJRefreshTrailer.m in Sources */ = {isa = PBXBuildFile; fileRef = 88E3200924839ABA00069FA7 /* MJRefreshTrailer.m */; };
88E3201124839B2300069FA7 /* MJRefreshStateTrailer.m in Sources */ = {isa = PBXBuildFile; fileRef = 88E3200E24839B2300069FA7 /* MJRefreshStateTrailer.m */; };
Expand Down Expand Up @@ -236,6 +240,8 @@
2DB2EA161BECBE6700D58F6A /* UIView+MJExtension.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "UIView+MJExtension.m"; sourceTree = "<group>"; };
6B8FB1A7250E610D00AF64B7 /* MJHorizontalCollectionViewController.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = MJHorizontalCollectionViewController.h; sourceTree = "<group>"; };
6B8FB1A8250E610D00AF64B7 /* MJHorizontalCollectionViewController.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = MJHorizontalCollectionViewController.m; sourceTree = "<group>"; };
7A698CD0274232A00028A4DD /* UICollectionViewLayout+MJRefresh.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "UICollectionViewLayout+MJRefresh.h"; sourceTree = "<group>"; };
7A698CD1274232A00028A4DD /* UICollectionViewLayout+MJRefresh.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = "UICollectionViewLayout+MJRefresh.m"; sourceTree = "<group>"; };
88E3200924839ABA00069FA7 /* MJRefreshTrailer.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MJRefreshTrailer.m; sourceTree = "<group>"; };
88E3200A24839ABA00069FA7 /* MJRefreshTrailer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MJRefreshTrailer.h; sourceTree = "<group>"; };
88E3200D24839B2300069FA7 /* MJRefreshNormalTrailer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MJRefreshNormalTrailer.h; sourceTree = "<group>"; };
Expand Down Expand Up @@ -450,18 +456,20 @@
2DB2E9F61BECBE6700D58F6A /* Custom */,
2DB2EA0D1BECBE6700D58F6A /* MJRefresh.bundle */,
2DB2EA0E1BECBE6700D58F6A /* MJRefresh.h */,
01A2CE0A21ACE01500BEE365 /* MJRefreshConfig.h */,
01A2CE0B21ACE01500BEE365 /* MJRefreshConfig.m */,
2DB2EA0F1BECBE6700D58F6A /* MJRefreshConst.h */,
2DB2EA101BECBE6700D58F6A /* MJRefreshConst.m */,
2D4698841D0EE6A400CB8025 /* NSBundle+MJRefresh.h */,
2D4698851D0EE6A400CB8025 /* NSBundle+MJRefresh.m */,
7A698CD0274232A00028A4DD /* UICollectionViewLayout+MJRefresh.h */,
7A698CD1274232A00028A4DD /* UICollectionViewLayout+MJRefresh.m */,
2DB2EA111BECBE6700D58F6A /* UIScrollView+MJExtension.h */,
2DB2EA121BECBE6700D58F6A /* UIScrollView+MJExtension.m */,
2DB2EA131BECBE6700D58F6A /* UIScrollView+MJRefresh.h */,
2DB2EA141BECBE6700D58F6A /* UIScrollView+MJRefresh.m */,
2DB2EA151BECBE6700D58F6A /* UIView+MJExtension.h */,
2DB2EA161BECBE6700D58F6A /* UIView+MJExtension.m */,
2D4698841D0EE6A400CB8025 /* NSBundle+MJRefresh.h */,
2D4698851D0EE6A400CB8025 /* NSBundle+MJRefresh.m */,
01A2CE0A21ACE01500BEE365 /* MJRefreshConfig.h */,
01A2CE0B21ACE01500BEE365 /* MJRefreshConfig.m */,
);
path = MJRefresh;
sourceTree = SOURCE_ROOT;
Expand Down Expand Up @@ -582,6 +590,7 @@
2D9DF4681F7CE2C20042D6DD /* MJRefresh.h in Headers */,
2D9DF4691F7CE2C20042D6DD /* MJRefreshConst.h in Headers */,
2D9DF46A1F7CE2C20042D6DD /* UIScrollView+MJExtension.h in Headers */,
7A698CD2274232A00028A4DD /* UICollectionViewLayout+MJRefresh.h in Headers */,
2D9DF46B1F7CE2C20042D6DD /* UIScrollView+MJRefresh.h in Headers */,
2D9DF46C1F7CE2C20042D6DD /* UIView+MJExtension.h in Headers */,
2D9DF46D1F7CE2C20042D6DD /* NSBundle+MJRefresh.h in Headers */,
Expand Down Expand Up @@ -738,6 +747,7 @@
84FC857E228037CE001C6728 /* MJRefreshConfig.m in Sources */,
2D9DF46F1F7CE2F90042D6DD /* MJRefreshAutoFooter.m in Sources */,
2D9DF4701F7CE2F90042D6DD /* MJRefreshBackFooter.m in Sources */,
7A698CD5274232A00028A4DD /* UICollectionViewLayout+MJRefresh.m in Sources */,
2D9DF4711F7CE2F90042D6DD /* MJRefreshComponent.m in Sources */,
2D9DF4721F7CE2F90042D6DD /* MJRefreshFooter.m in Sources */,
2D9DF4731F7CE2F90042D6DD /* MJRefreshHeader.m in Sources */,
Expand Down Expand Up @@ -768,6 +778,7 @@
2D9BEB0F1BB15F4A00AED473 /* MJDIYHeader.m in Sources */,
2D9BEB181BB15F4A00AED473 /* MJTableViewController.m in Sources */,
2DB2EA261BECBE6700D58F6A /* MJRefreshConst.m in Sources */,
7A698CD3274232A00028A4DD /* UICollectionViewLayout+MJRefresh.m in Sources */,
2D9BEB0A1BB15F4A00AED473 /* MJChiBaoZiFooter.m in Sources */,
2D9BEB121BB15F4A00AED473 /* MJExampleWindow.m in Sources */,
2DB2EA221BECBE6700D58F6A /* MJRefreshGifHeader.m in Sources */,
Expand Down Expand Up @@ -814,6 +825,7 @@
buildActionMask = 2147483647;
files = (
2DA7F9451AA6B4C4005627AB /* MJRefreshExampleTests.m in Sources */,
7A698CD4274232A00028A4DD /* UICollectionViewLayout+MJRefresh.m in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
Expand Down
14 changes: 11 additions & 3 deletions MJRefreshExample/Classes/Second/MJCollectionViewController.m
Original file line number Diff line number Diff line change
Expand Up @@ -57,11 +57,19 @@ - (void)example21

// 模拟延迟加载数据,因此2秒后才调用(真实开发中,可以移除这段gcd代码)
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(MJDuration * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
[weakSelf.collectionView reloadData];
// [weakSelf.collectionView reloadData];
// [weakSelf.collectionView.mj_footer endRefreshing];

/// https://github.com/CoderMJLee/MJRefresh/issues/1552
[weakSelf.collectionView performBatchUpdates:^{
[weakSelf.collectionView reloadSections:[NSIndexSet indexSetWithIndex:0]];
} completion:^(BOOL finished) {
// 结束刷新
[weakSelf.collectionView.mj_footer endRefreshing];
}];

// 结束刷新
[weakSelf.collectionView.mj_footer endRefreshing];
});

}] setAnimationDisabled]
autoChangeTransparency:YES]
linkTo:self.collectionView];
Expand Down