From 55d6d95fd66521d061c3eee6ba038bb30aa67ed1 Mon Sep 17 00:00:00 2001 From: jiasong <593908937@qq.com> Date: Mon, 15 Nov 2021 14:23:33 +0800 Subject: [PATCH 1/7] =?UTF-8?q?=E4=BF=AE=E5=A4=8D=20https://github.com/Cod?= =?UTF-8?q?erMJLee/MJRefresh/issues/1552=20=E7=9A=84=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- MJRefresh/Base/MJRefreshAutoFooter.m | 11 ++++-- MJRefresh/Base/MJRefreshBackFooter.m | 11 ++++-- MJRefresh/MJRefreshConst.h | 26 ++++++++++++++ MJRefresh/UICollectionViewLayout+MJRefresh.h | 17 +++++++++ MJRefresh/UICollectionViewLayout+MJRefresh.m | 36 +++++++++++++++++++ MJRefreshExample.xcodeproj/project.pbxproj | 20 ++++++++--- .../Second/MJCollectionViewController.m | 14 ++++++-- 7 files changed, 124 insertions(+), 11 deletions(-) create mode 100644 MJRefresh/UICollectionViewLayout+MJRefresh.h create mode 100644 MJRefresh/UICollectionViewLayout+MJRefresh.m diff --git a/MJRefresh/Base/MJRefreshAutoFooter.m b/MJRefresh/Base/MJRefreshAutoFooter.m index 583f2555..66b4901e 100644 --- a/MJRefresh/Base/MJRefreshAutoFooter.m +++ b/MJRefresh/Base/MJRefreshAutoFooter.m @@ -63,9 +63,16 @@ - (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; + self.mj_y = contentHeight + self.ignoredScrollViewContentInsetBottom; } - (void)scrollViewContentOffsetDidChange:(NSDictionary *)change diff --git a/MJRefresh/Base/MJRefreshBackFooter.m b/MJRefresh/Base/MJRefreshBackFooter.m index 028d1181..7df8efef 100644 --- a/MJRefresh/Base/MJRefreshBackFooter.m +++ b/MJRefresh/Base/MJRefreshBackFooter.m @@ -71,9 +71,16 @@ - (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; // 设置位置和尺寸 diff --git a/MJRefresh/MJRefreshConst.h b/MJRefresh/MJRefreshConst.h index 2ccff476..042e88f2 100644 --- a/MJRefresh/MJRefreshConst.h +++ b/MJRefresh/MJRefreshConst.h @@ -1,6 +1,7 @@ // 代码地址: https://github.com/CoderMJLee/MJRefresh #import #import +#import // 弱引用 #define MJWeakSelf __weak typeof(self) weakSelf = self; @@ -74,3 +75,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; +} diff --git a/MJRefresh/UICollectionViewLayout+MJRefresh.h b/MJRefresh/UICollectionViewLayout+MJRefresh.h new file mode 100644 index 00000000..7c6ea417 --- /dev/null +++ b/MJRefresh/UICollectionViewLayout+MJRefresh.h @@ -0,0 +1,17 @@ +// +// UICollectionViewLayout+MJRefresh.h +// MJRefreshExample +// +// Created by jiasong on 2021/11/15. +// Copyright © 2021 小码哥. All rights reserved. +// + +#import + +NS_ASSUME_NONNULL_BEGIN + +@interface UICollectionViewLayout (MJRefresh) + +@end + +NS_ASSUME_NONNULL_END diff --git a/MJRefresh/UICollectionViewLayout+MJRefresh.m b/MJRefresh/UICollectionViewLayout+MJRefresh.m new file mode 100644 index 00000000..c385824b --- /dev/null +++ b/MJRefresh/UICollectionViewLayout+MJRefresh.m @@ -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 { + __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]; + } +} + +@end diff --git a/MJRefreshExample.xcodeproj/project.pbxproj b/MJRefreshExample.xcodeproj/project.pbxproj index 0a218459..2d080b2c 100644 --- a/MJRefreshExample.xcodeproj/project.pbxproj +++ b/MJRefreshExample.xcodeproj/project.pbxproj @@ -95,6 +95,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 */; }; + 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 */; }; @@ -224,6 +228,8 @@ 2DB2EA161BECBE6700D58F6A /* UIView+MJExtension.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "UIView+MJExtension.m"; sourceTree = ""; }; 6B8FB1A7250E610D00AF64B7 /* MJHorizontalCollectionViewController.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = MJHorizontalCollectionViewController.h; sourceTree = ""; }; 6B8FB1A8250E610D00AF64B7 /* MJHorizontalCollectionViewController.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = MJHorizontalCollectionViewController.m; sourceTree = ""; }; + 7A698CD0274232A00028A4DD /* UICollectionViewLayout+MJRefresh.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "UICollectionViewLayout+MJRefresh.h"; sourceTree = ""; }; + 7A698CD1274232A00028A4DD /* UICollectionViewLayout+MJRefresh.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = "UICollectionViewLayout+MJRefresh.m"; sourceTree = ""; }; 88E3200924839ABA00069FA7 /* MJRefreshTrailer.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MJRefreshTrailer.m; sourceTree = ""; }; 88E3200A24839ABA00069FA7 /* MJRefreshTrailer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MJRefreshTrailer.h; sourceTree = ""; }; 88E3200D24839B2300069FA7 /* MJRefreshNormalTrailer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MJRefreshNormalTrailer.h; sourceTree = ""; }; @@ -429,18 +435,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; @@ -560,6 +568,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 */, @@ -706,6 +715,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 */, @@ -736,6 +746,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 */, @@ -782,6 +793,7 @@ buildActionMask = 2147483647; files = ( 2DA7F9451AA6B4C4005627AB /* MJRefreshExampleTests.m in Sources */, + 7A698CD4274232A00028A4DD /* UICollectionViewLayout+MJRefresh.m in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; diff --git a/MJRefreshExample/Classes/Second/MJCollectionViewController.m b/MJRefreshExample/Classes/Second/MJCollectionViewController.m index 00a13d5b..2e64ab0d 100644 --- a/MJRefreshExample/Classes/Second/MJCollectionViewController.m +++ b/MJRefreshExample/Classes/Second/MJCollectionViewController.m @@ -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]; From 794681289f8d6483b39a9100b82ea0ef15636949 Mon Sep 17 00:00:00 2001 From: jiasong <593908937@qq.com> Date: Mon, 15 Nov 2021 14:27:25 +0800 Subject: [PATCH 2/7] =?UTF-8?q?=E5=88=A4=E6=96=ADmj=5Fy=E4=B8=8D=E7=9B=B8?= =?UTF-8?q?=E5=90=8C=E6=97=B6=E6=89=8D=E5=8E=BB=E8=B5=8B=E5=80=BC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- MJRefresh/Base/MJRefreshAutoFooter.m | 5 ++++- MJRefresh/Base/MJRefreshBackFooter.m | 5 ++++- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/MJRefresh/Base/MJRefreshAutoFooter.m b/MJRefresh/Base/MJRefreshAutoFooter.m index 66b4901e..703a5736 100644 --- a/MJRefresh/Base/MJRefreshAutoFooter.m +++ b/MJRefresh/Base/MJRefreshAutoFooter.m @@ -72,7 +72,10 @@ - (void)scrollViewContentSizeDidChange:(NSDictionary *)change contentHeight = self.scrollView.mj_contentH; } // 设置位置 - self.mj_y = contentHeight + self.ignoredScrollViewContentInsetBottom; + CGFloat y = contentHeight + self.ignoredScrollViewContentInsetBottom; + if (self.mj_y != y) { + self.mj_y = y; + } } - (void)scrollViewContentOffsetDidChange:(NSDictionary *)change diff --git a/MJRefresh/Base/MJRefreshBackFooter.m b/MJRefresh/Base/MJRefreshBackFooter.m index 7df8efef..0478c78c 100644 --- a/MJRefresh/Base/MJRefreshBackFooter.m +++ b/MJRefresh/Base/MJRefreshBackFooter.m @@ -84,7 +84,10 @@ - (void)scrollViewContentSizeDidChange:(NSDictionary *)change // 表格的高度 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 From 396677a804633f87e5e02f49c8b8ff229e228679 Mon Sep 17 00:00:00 2001 From: jiasong <593908937@qq.com> Date: Tue, 16 Nov 2021 11:42:23 +0800 Subject: [PATCH 3/7] =?UTF-8?q?1=E3=80=81=E4=BF=AE=E5=A4=8D=EF=BC=9Amj=5Ff?= =?UTF-8?q?inalizeCollectionViewUpdates=E6=9C=AA=E8=B0=83=E7=94=A8?= =?UTF-8?q?=E5=8E=9F=E5=A7=8B=E5=AE=9E=E7=8E=B0=E7=9A=84=E9=97=AE=E9=A2=98?= =?UTF-8?q?=202=E3=80=81=E6=94=B9=E8=BF=9B=EF=BC=9A=E5=BD=93=E5=89=8D?= =?UTF-8?q?=E5=90=8EcontentSize=E4=B8=8D=E4=B8=80=E8=87=B4=E6=97=B6?= =?UTF-8?q?=E6=89=8D=E5=8E=BB=E6=9B=B4=E6=96=B0footer=E7=9A=84=E9=AB=98?= =?UTF-8?q?=E5=BA=A6=203=E3=80=81=E6=94=B9=E8=BF=9B=EF=BC=9A=E5=8E=BB?= =?UTF-8?q?=E6=8E=89MJRefreshExampleTests=E4=B8=ADUICollectionViewLayout+M?= =?UTF-8?q?JRefresh=E6=96=87=E4=BB=B6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- MJRefresh/UICollectionViewLayout+MJRefresh.m | 10 +++++++--- MJRefreshExample.xcodeproj/project.pbxproj | 2 -- 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/MJRefresh/UICollectionViewLayout+MJRefresh.m b/MJRefresh/UICollectionViewLayout+MJRefresh.m index c385824b..201aab16 100644 --- a/MJRefresh/UICollectionViewLayout+MJRefresh.m +++ b/MJRefresh/UICollectionViewLayout+MJRefresh.m @@ -20,11 +20,15 @@ + (void)load { } - (void)mj_finalizeCollectionViewUpdates { + [self mj_finalizeCollectionViewUpdates]; + __kindof MJRefreshFooter *footer = self.collectionView.mj_footer; - if (footer != nil && footer.isRefreshing) { + CGSize newSize = self.collectionViewContentSize; + CGSize oldSize = self.collectionView.contentSize; + if (footer != nil && footer.isRefreshing && !CGSizeEqualToSize(newSize, oldSize)) { NSDictionary *changed = @{ - NSKeyValueChangeNewKey: [NSValue valueWithCGSize:self.collectionViewContentSize], - NSKeyValueChangeOldKey: [NSValue valueWithCGSize:self.collectionView.contentSize], + NSKeyValueChangeNewKey: [NSValue valueWithCGSize:newSize], + NSKeyValueChangeOldKey: [NSValue valueWithCGSize:oldSize], }; [CATransaction begin]; [CATransaction setDisableActions:YES]; diff --git a/MJRefreshExample.xcodeproj/project.pbxproj b/MJRefreshExample.xcodeproj/project.pbxproj index 4b2e5c7c..39b94d6c 100644 --- a/MJRefreshExample.xcodeproj/project.pbxproj +++ b/MJRefreshExample.xcodeproj/project.pbxproj @@ -103,7 +103,6 @@ 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 */; }; 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 */; }; @@ -825,7 +824,6 @@ buildActionMask = 2147483647; files = ( 2DA7F9451AA6B4C4005627AB /* MJRefreshExampleTests.m in Sources */, - 7A698CD4274232A00028A4DD /* UICollectionViewLayout+MJRefresh.m in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; From 5c576d1402da604f54a6fd6e6ee6d564312c12a5 Mon Sep 17 00:00:00 2001 From: jiasong <593908937@qq.com> Date: Tue, 16 Nov 2021 11:55:11 +0800 Subject: [PATCH 4/7] =?UTF-8?q?=E5=8E=BB=E6=8E=89footer.isRefreshing?= =?UTF-8?q?=E7=9A=84=E5=88=A4=E6=96=AD=EF=BC=8CcontentSize=E5=8F=98?= =?UTF-8?q?=E5=8A=A8=E5=B0=B1=E5=BA=94=E8=AF=A5=E5=8E=BB=E6=9B=B4=E6=96=B0?= =?UTF-8?q?footer?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- MJRefresh/UICollectionViewLayout+MJRefresh.m | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/MJRefresh/UICollectionViewLayout+MJRefresh.m b/MJRefresh/UICollectionViewLayout+MJRefresh.m index 201aab16..d2f2ba9f 100644 --- a/MJRefresh/UICollectionViewLayout+MJRefresh.m +++ b/MJRefresh/UICollectionViewLayout+MJRefresh.m @@ -25,7 +25,7 @@ - (void)mj_finalizeCollectionViewUpdates { __kindof MJRefreshFooter *footer = self.collectionView.mj_footer; CGSize newSize = self.collectionViewContentSize; CGSize oldSize = self.collectionView.contentSize; - if (footer != nil && footer.isRefreshing && !CGSizeEqualToSize(newSize, oldSize)) { + if (footer != nil && !CGSizeEqualToSize(newSize, oldSize)) { NSDictionary *changed = @{ NSKeyValueChangeNewKey: [NSValue valueWithCGSize:newSize], NSKeyValueChangeOldKey: [NSValue valueWithCGSize:oldSize], From 2698fcde5a211d18dd5ea82f0d63463685966f00 Mon Sep 17 00:00:00 2001 From: Frank <472730949@qq.com> Date: Wed, 17 Nov 2021 17:57:03 +0800 Subject: [PATCH 5/7] `scrollViewContentSizeDidChange` method should be guaranteed that change value is a `NSValue` by framework. --- MJRefresh/Base/MJRefreshAutoFooter.m | 11 +++-------- MJRefresh/Base/MJRefreshBackFooter.m | 15 +++++---------- 2 files changed, 8 insertions(+), 18 deletions(-) diff --git a/MJRefresh/Base/MJRefreshAutoFooter.m b/MJRefresh/Base/MJRefreshAutoFooter.m index 703a5736..cf1748a5 100644 --- a/MJRefresh/Base/MJRefreshAutoFooter.m +++ b/MJRefresh/Base/MJRefreshAutoFooter.m @@ -63,14 +63,9 @@ - (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; - } + + CGSize size = [change[NSKeyValueChangeNewKey] CGSizeValue]; + CGFloat contentHeight = size.height == 0 ? self.scrollView.mj_contentH : size.height; // 设置位置 CGFloat y = contentHeight + self.ignoredScrollViewContentInsetBottom; if (self.mj_y != y) { diff --git a/MJRefresh/Base/MJRefreshBackFooter.m b/MJRefresh/Base/MJRefreshBackFooter.m index 0478c78c..970da766 100644 --- a/MJRefresh/Base/MJRefreshBackFooter.m +++ b/MJRefresh/Base/MJRefreshBackFooter.m @@ -71,19 +71,14 @@ - (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; - } + + CGSize size = [change[NSKeyValueChangeNewKey] CGSizeValue]; + CGFloat contentHeight = size.height == 0 ? self.scrollView.mj_contentH : size.height; // 内容的高度 - contentHeight = contentHeight + self.ignoredScrollViewContentInsetBottom; + contentHeight += self.ignoredScrollViewContentInsetBottom; // 表格的高度 CGFloat scrollHeight = self.scrollView.mj_h - self.scrollViewOriginalInset.top - self.scrollViewOriginalInset.bottom + self.ignoredScrollViewContentInsetBottom; - // 设置位置和尺寸 + // 设置位置 CGFloat y = MAX(contentHeight, scrollHeight); if (self.mj_y != y) { self.mj_y = y; From 95c818bc60455c85db190f4057b79d5121d5062a Mon Sep 17 00:00:00 2001 From: Frank <472730949@qq.com> Date: Wed, 17 Nov 2021 18:17:48 +0800 Subject: [PATCH 6/7] Added some comment for new function. --- MJRefresh/MJRefreshConst.h | 9 ++++++--- MJRefresh/UICollectionViewLayout+MJRefresh.h | 5 ++++- MJRefresh/UICollectionViewLayout+MJRefresh.m | 8 ++++++-- .../Classes/Second/MJCollectionViewController.m | 3 ++- 4 files changed, 18 insertions(+), 7 deletions(-) diff --git a/MJRefresh/MJRefreshConst.h b/MJRefresh/MJRefreshConst.h index 6e12c01d..2916ddab 100644 --- a/MJRefresh/MJRefreshConst.h +++ b/MJRefresh/MJRefreshConst.h @@ -81,9 +81,12 @@ typeof(weakSelf) self = weakSelf; \ {x} \ }); -// runtime -CG_INLINE BOOL -MJRefreshExchangeImplementationsInTwoClasses(Class _fromClass, SEL _originSelector, Class _toClass, SEL _newSelector) { +/// 替换方法实现 +/// @param _fromClass 源类 +/// @param _originSelector 源类的 Selector +/// @param _toClass 目标类 +/// @param _newSelector 目标类的 Selector +CG_INLINE BOOL MJRefreshExchangeImplementations(Class _fromClass, SEL _originSelector, Class _toClass, SEL _newSelector) { if (!_fromClass || !_toClass) { return NO; } diff --git a/MJRefresh/UICollectionViewLayout+MJRefresh.h b/MJRefresh/UICollectionViewLayout+MJRefresh.h index 7c6ea417..df0423d0 100644 --- a/MJRefresh/UICollectionViewLayout+MJRefresh.h +++ b/MJRefresh/UICollectionViewLayout+MJRefresh.h @@ -1,6 +1,9 @@ // // UICollectionViewLayout+MJRefresh.h -// MJRefreshExample +// +// 该类是用来解决 Footer 在底端加载完成后, 仍停留在原处的 bug. +// 此问题出现在 iOS 14 及以下系统上. +// Reference: https://github.com/CoderMJLee/MJRefresh/issues/1552 // // Created by jiasong on 2021/11/15. // Copyright © 2021 小码哥. All rights reserved. diff --git a/MJRefresh/UICollectionViewLayout+MJRefresh.m b/MJRefresh/UICollectionViewLayout+MJRefresh.m index d2f2ba9f..94ebaf68 100644 --- a/MJRefresh/UICollectionViewLayout+MJRefresh.m +++ b/MJRefresh/UICollectionViewLayout+MJRefresh.m @@ -1,6 +1,9 @@ // // UICollectionViewLayout+MJRefresh.m -// MJRefreshExample +// +// 该类是用来解决 Footer 在底端加载完成后, 仍停留在原处的 bug. +// 此问题出现在 iOS 14 及以下系统上. +// Reference: https://github.com/CoderMJLee/MJRefresh/issues/1552 // // Created by jiasong on 2021/11/15. // Copyright © 2021 小码哥. All rights reserved. @@ -15,7 +18,8 @@ @implementation UICollectionViewLayout (MJRefresh) + (void)load { static dispatch_once_t onceToken; dispatch_once(&onceToken, ^{ - MJRefreshExchangeImplementationsInTwoClasses([self class], @selector(finalizeCollectionViewUpdates), [self class], @selector(mj_finalizeCollectionViewUpdates)); + MJRefreshExchangeImplementations(self.class, @selector(finalizeCollectionViewUpdates), + self.class, @selector(mj_finalizeCollectionViewUpdates)); }); } diff --git a/MJRefreshExample/Classes/Second/MJCollectionViewController.m b/MJRefreshExample/Classes/Second/MJCollectionViewController.m index 2e64ab0d..2835af83 100644 --- a/MJRefreshExample/Classes/Second/MJCollectionViewController.m +++ b/MJRefreshExample/Classes/Second/MJCollectionViewController.m @@ -60,7 +60,6 @@ - (void)example21 // [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) { @@ -73,6 +72,8 @@ - (void)example21 }] setAnimationDisabled] autoChangeTransparency:YES] linkTo:self.collectionView]; + + [self.collectionView.mj_header beginRefreshing]; } #pragma mark - 数据相关 From 7a97a6a0c90b83bed6ea5cb4b2bf374dab77d61c Mon Sep 17 00:00:00 2001 From: Frank <472730949@qq.com> Date: Wed, 17 Nov 2021 18:23:28 +0800 Subject: [PATCH 7/7] Re-Indent code structure --- MJRefresh/MJRefreshConst.h | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/MJRefresh/MJRefreshConst.h b/MJRefresh/MJRefreshConst.h index 2916ddab..6881115c 100644 --- a/MJRefresh/MJRefreshConst.h +++ b/MJRefresh/MJRefreshConst.h @@ -86,7 +86,9 @@ typeof(weakSelf) self = weakSelf; \ /// @param _originSelector 源类的 Selector /// @param _toClass 目标类 /// @param _newSelector 目标类的 Selector -CG_INLINE BOOL MJRefreshExchangeImplementations(Class _fromClass, SEL _originSelector, Class _toClass, SEL _newSelector) { +CG_INLINE BOOL MJRefreshExchangeImplementations( + Class _fromClass, SEL _originSelector, + Class _toClass, SEL _newSelector) { if (!_fromClass || !_toClass) { return NO; } @@ -97,10 +99,13 @@ CG_INLINE BOOL MJRefreshExchangeImplementations(Class _fromClass, SEL _originSel return NO; } - BOOL isAddedMethod = class_addMethod(_fromClass, _originSelector, method_getImplementation(newMethod), method_getTypeEncoding(newMethod)); + 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) {}); + IMP emptyIMP = imp_implementationWithBlock(^(id selfObject) {}); + IMP oriMethodIMP = method_getImplementation(oriMethod) ?: emptyIMP; const char *oriMethodTypeEncoding = method_getTypeEncoding(oriMethod) ?: "v@:"; class_replaceMethod(_toClass, _newSelector, oriMethodIMP, oriMethodTypeEncoding); } else {