|
|
@@ -68,7 +68,6 @@ - (void)resetInset {
|
|
|
}
|
|
|
}
|
|
|
|
|
|
-
|
|
|
- (void)scrollViewContentOffsetDidChange:(NSDictionary *)change
|
|
|
{
|
|
|
[super scrollViewContentOffsetDidChange:change];
|
|
|
@@ -114,6 +113,45 @@ - (void)scrollViewContentOffsetDidChange:(NSDictionary *)change
|
|
|
|
|
|
- (void)setState:(MJRefreshState)state
|
|
|
{
|
|
|
+ MJRefreshCheckState
|
|
|
+
|
|
|
+ // 根据状态做事情
|
|
|
+ if (state == MJRefreshStateIdle) {
|
|
|
+ if (oldState != MJRefreshStateRefreshing) return;
|
|
|
+
|
|
|
+ [self headerEndingAction];
|
|
|
+ } else if (state == MJRefreshStateRefreshing) {
|
|
|
+ [self headerRefreshingAction];
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+- (void)headerEndingAction {
|
|
|
+ // 保存刷新时间
|
|
|
+ [[NSUserDefaults standardUserDefaults] setObject:[NSDate date] forKey:self.lastUpdatedTimeKey];
|
|
|
+ [[NSUserDefaults standardUserDefaults] synchronize];
|
|
|
+
|
|
|
+ // 默认使用 UIViewAnimation 动画
|
|
|
+ if (!self.isCollectionViewAnimationBug) {
|
|
|
+ // 恢复inset和offset
|
|
|
+ [UIView animateWithDuration:MJRefreshSlowAnimationDuration animations:^{
|
|
|
+ self.scrollView.mj_insetT += self.insetTDelta;
|
|
|
+
|
|
|
+ if (self.endRefreshingAnimationBeginAction) {
|
|
|
+ self.endRefreshingAnimationBeginAction();
|
|
|
+ }
|
|
|
+ // 自动调整透明度
|
|
|
+ if (self.isAutomaticallyChangeAlpha) self.alpha = 0.0;
|
|
|
+ } completion:^(BOOL finished) {
|
|
|
+ self.pullingPercent = 0.0;
|
|
|
+
|
|
|
+ if (self.endRefreshingCompletionBlock) {
|
|
|
+ self.endRefreshingCompletionBlock();
|
|
|
+ }
|
|
|
+ }];
|
|
|
+
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
/**
|
|
|
这个解决方法的思路出自 https://github.com/CoderMJLee/MJRefresh/pull/844
|
|
|
修改了用+ [UIView animateWithDuration: animations:]实现的修改contentInset的动画
|
|
|
@@ -123,72 +161,85 @@ - (void)setState:(MJRefreshState)state
|
|
|
同时, 处理了 Refreshing 中的动画替换.
|
|
|
*/
|
|
|
|
|
|
- MJRefreshCheckState
|
|
|
+ // 由于修改 Inset 会导致 self.pullingPercent 联动设置 self.alpha, 故提前获取 alpha 值, 后续用于还原 alpha 动画
|
|
|
+ CGFloat viewAlpha = self.alpha;
|
|
|
|
|
|
- // 根据状态做事情
|
|
|
- if (state == MJRefreshStateIdle) {
|
|
|
- if (oldState != MJRefreshStateRefreshing) return;
|
|
|
- // 保存刷新时间
|
|
|
- [[NSUserDefaults standardUserDefaults] setObject:[NSDate date] forKey:self.lastUpdatedTimeKey];
|
|
|
- [[NSUserDefaults standardUserDefaults] synchronize];
|
|
|
+ self.scrollView.mj_insetT += self.insetTDelta;
|
|
|
+ // 禁用交互, 如果不禁用可能会引起渲染问题.
|
|
|
+ self.scrollView.userInteractionEnabled = NO;
|
|
|
|
|
|
- // 由于修改 Inset 会导致 self.pullingPercent 联动设置 self.alpha, 故提前获取 alpha 值, 后续用于还原 alpha 动画
|
|
|
- CGFloat viewAlpha = self.alpha;
|
|
|
-
|
|
|
- self.scrollView.mj_insetT += self.insetTDelta;
|
|
|
+ //CAAnimation keyPath 不支持 contentInset 用Bounds的动画代替
|
|
|
+ CABasicAnimation *boundsAnimation = [CABasicAnimation animationWithKeyPath:@"bounds"];
|
|
|
+ boundsAnimation.fromValue = [NSValue valueWithCGRect:CGRectOffset(self.scrollView.bounds, 0, self.insetTDelta)];
|
|
|
+ boundsAnimation.duration = MJRefreshSlowAnimationDuration;
|
|
|
+ //在delegate里移除
|
|
|
+ boundsAnimation.removedOnCompletion = NO;
|
|
|
+ boundsAnimation.fillMode = kCAFillModeBoth;
|
|
|
+ boundsAnimation.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut];
|
|
|
+ boundsAnimation.delegate = self;
|
|
|
+ [boundsAnimation setValue:MJRefreshHeaderRefreshing2IdleBoundsKey forKey:@"identity"];
|
|
|
+
|
|
|
+ [self.scrollView.layer addAnimation:boundsAnimation forKey:MJRefreshHeaderRefreshing2IdleBoundsKey];
|
|
|
+
|
|
|
+ if (self.endRefreshingAnimationBeginAction) {
|
|
|
+ self.endRefreshingAnimationBeginAction();
|
|
|
+ }
|
|
|
+ // 自动调整透明度的动画
|
|
|
+ if (self.isAutomaticallyChangeAlpha) {
|
|
|
+ CABasicAnimation *opacityAnimation = [CABasicAnimation animationWithKeyPath:@"opacity"];
|
|
|
+ opacityAnimation.fromValue = @(viewAlpha);
|
|
|
+ opacityAnimation.toValue = @(0.0);
|
|
|
+ opacityAnimation.duration = MJRefreshSlowAnimationDuration;
|
|
|
+ opacityAnimation.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut];
|
|
|
+ [self.layer addAnimation:opacityAnimation forKey:@"MJRefreshHeaderRefreshing2IdleOpacity"];
|
|
|
+
|
|
|
+ // 由于修改了 inset 导致, pullingPercent 被设置值, alpha 已经被提前修改为 0 了. 所以这里不用置 0, 但为了代码的严谨性, 不依赖其他的特殊实现方式, 这里还是置 0.
|
|
|
+ self.alpha = 0;
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+- (void)headerRefreshingAction {
|
|
|
+ // 默认使用 UIViewAnimation 动画
|
|
|
+ if (!self.isCollectionViewAnimationBug) {
|
|
|
+ MJRefreshDispatchAsyncOnMainQueue({
|
|
|
+ [UIView animateWithDuration:MJRefreshFastAnimationDuration animations:^{
|
|
|
+ if (self.scrollView.panGestureRecognizer.state != UIGestureRecognizerStateCancelled) {
|
|
|
+ CGFloat top = self.scrollViewOriginalInset.top + self.mj_h;
|
|
|
+ // 增加滚动区域top
|
|
|
+ self.scrollView.mj_insetT = top;
|
|
|
+ // 设置滚动位置
|
|
|
+ CGPoint offset = self.scrollView.contentOffset;
|
|
|
+ offset.y = -top;
|
|
|
+ [self.scrollView setContentOffset:offset animated:NO];
|
|
|
+ }
|
|
|
+ } completion:^(BOOL finished) {
|
|
|
+ [self executeRefreshingCallback];
|
|
|
+ }];
|
|
|
+ })
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ if (self.scrollView.panGestureRecognizer.state != UIGestureRecognizerStateCancelled) {
|
|
|
+ CGFloat top = self.scrollViewOriginalInset.top + self.mj_h;
|
|
|
// 禁用交互, 如果不禁用可能会引起渲染问题.
|
|
|
self.scrollView.userInteractionEnabled = NO;
|
|
|
- //CAAnimation keyPath 不支持 contentInset 用Bounds的动画代替
|
|
|
+
|
|
|
+ // CAAnimation keyPath不支持 contentOffset 用Bounds的动画代替
|
|
|
CABasicAnimation *boundsAnimation = [CABasicAnimation animationWithKeyPath:@"bounds"];
|
|
|
- boundsAnimation.fromValue = [NSValue valueWithCGRect:CGRectOffset(self.scrollView.bounds, 0, self.insetTDelta)];
|
|
|
- boundsAnimation.duration = MJRefreshSlowAnimationDuration;
|
|
|
+ CGRect bounds = self.scrollView.bounds;
|
|
|
+ bounds.origin.y = -top;
|
|
|
+ boundsAnimation.fromValue = [NSValue valueWithCGRect:self.scrollView.bounds];
|
|
|
+ boundsAnimation.toValue = [NSValue valueWithCGRect:bounds];
|
|
|
+ boundsAnimation.duration = MJRefreshFastAnimationDuration;
|
|
|
//在delegate里移除
|
|
|
boundsAnimation.removedOnCompletion = NO;
|
|
|
boundsAnimation.fillMode = kCAFillModeBoth;
|
|
|
boundsAnimation.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut];
|
|
|
boundsAnimation.delegate = self;
|
|
|
- [boundsAnimation setValue:MJRefreshHeaderRefreshing2IdleBoundsKey forKey:@"identity"];
|
|
|
-
|
|
|
- [self.scrollView.layer addAnimation:boundsAnimation forKey:MJRefreshHeaderRefreshing2IdleBoundsKey];
|
|
|
-
|
|
|
- if (self.endRefreshingAnimationBeginAction) {
|
|
|
- self.endRefreshingAnimationBeginAction();
|
|
|
- }
|
|
|
- // 自动调整透明度的动画
|
|
|
- if (self.isAutomaticallyChangeAlpha) {
|
|
|
- CABasicAnimation *opacityAnimation = [CABasicAnimation animationWithKeyPath:@"opacity"];
|
|
|
- opacityAnimation.fromValue = @(viewAlpha);
|
|
|
- opacityAnimation.toValue = @(0.0);
|
|
|
- opacityAnimation.duration = MJRefreshSlowAnimationDuration;
|
|
|
- opacityAnimation.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut];
|
|
|
- [self.layer addAnimation:opacityAnimation forKey:@"MJRefreshHeaderRefreshing2IdleOpacity"];
|
|
|
-
|
|
|
- // 由于修改了 inset 导致, pullingPercent 被设置值, alpha 已经被提前修改为 0 了. 所以这里不用置 0, 但为了代码的严谨性, 不依赖其他的特殊实现方式, 这里还是置 0.
|
|
|
- self.alpha = 0;
|
|
|
- }
|
|
|
- } else if (state == MJRefreshStateRefreshing) {
|
|
|
- if (self.scrollView.panGestureRecognizer.state != UIGestureRecognizerStateCancelled) {
|
|
|
- CGFloat top = self.scrollViewOriginalInset.top + self.mj_h;
|
|
|
- // 禁用交互, 如果不禁用可能会引起渲染问题.
|
|
|
- self.scrollView.userInteractionEnabled = NO;
|
|
|
-
|
|
|
- // CAAnimation keyPath不支持contentOffset 用Bounds的动画代替
|
|
|
- CABasicAnimation *boundsAnimation = [CABasicAnimation animationWithKeyPath:@"bounds"];
|
|
|
- CGRect bounds = self.scrollView.bounds;
|
|
|
- bounds.origin.y = -top;
|
|
|
- boundsAnimation.fromValue = [NSValue valueWithCGRect:self.scrollView.bounds];
|
|
|
- boundsAnimation.toValue = [NSValue valueWithCGRect:bounds];
|
|
|
- boundsAnimation.duration = MJRefreshFastAnimationDuration;
|
|
|
- //在delegate里移除
|
|
|
- boundsAnimation.removedOnCompletion = NO;
|
|
|
- [boundsAnimation setValue:MJRefreshHeaderRefreshingBoundsKey forKey:@"identity"];
|
|
|
- boundsAnimation.fillMode = kCAFillModeBoth;
|
|
|
- boundsAnimation.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut];
|
|
|
- boundsAnimation.delegate = self;
|
|
|
- [self.scrollView.layer addAnimation:boundsAnimation forKey:MJRefreshHeaderRefreshingBoundsKey];
|
|
|
- } else {
|
|
|
- [self executeRefreshingCallback];
|
|
|
- }
|
|
|
+ [boundsAnimation setValue:MJRefreshHeaderRefreshingBoundsKey forKey:@"identity"];
|
|
|
+ [self.scrollView.layer addAnimation:boundsAnimation forKey:MJRefreshHeaderRefreshingBoundsKey];
|
|
|
+ } else {
|
|
|
+ [self executeRefreshingCallback];
|
|
|
}
|
|
|
}
|
|
|
|
|
|
@@ -201,8 +252,7 @@ - (void)animationDidStop:(CAAnimation *)anim finished:(BOOL)flag {
|
|
|
if (self.endRefreshingCompletionBlock) {
|
|
|
self.endRefreshingCompletionBlock();
|
|
|
}
|
|
|
- }
|
|
|
- if ([identity isEqualToString:MJRefreshHeaderRefreshingBoundsKey]) {
|
|
|
+ } else if ([identity isEqualToString:MJRefreshHeaderRefreshingBoundsKey]) {
|
|
|
CGFloat top = self.scrollViewOriginalInset.top + self.mj_h;
|
|
|
self.scrollView.mj_insetT = top;
|
|
|
// 设置最终滚动位置
|
|
|
@@ -219,7 +269,6 @@ - (void)animationDidStop:(CAAnimation *)anim finished:(BOOL)flag {
|
|
|
|
|
|
if ([self.scrollView.layer animationForKey:MJRefreshHeaderRefreshingBoundsKey]) {
|
|
|
[self.scrollView.layer removeAnimationForKey:MJRefreshHeaderRefreshingBoundsKey];
|
|
|
-
|
|
|
}
|
|
|
}
|
|
|
|