移除 MJRefresh 依赖,恢复 SwiftUI 系统下拉刷新。
同时收紧各 ViewModel 内部 isLoading 可见性,避免不必要的视图刷新。 Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
1
Podfile
1
Podfile
@ -7,7 +7,6 @@ target 'suixinkan' do
|
|||||||
pod 'AMap3DMap-NO-IDFA', '~> 11.1'
|
pod 'AMap3DMap-NO-IDFA', '~> 11.1'
|
||||||
pod 'AMapSearch-NO-IDFA', '~> 9.7'
|
pod 'AMapSearch-NO-IDFA', '~> 9.7'
|
||||||
pod 'AMapLocation-NO-IDFA', '~> 2.11'
|
pod 'AMapLocation-NO-IDFA', '~> 2.11'
|
||||||
pod 'MJRefresh', '~> 3.7'
|
|
||||||
|
|
||||||
target 'suixinkanTests' do
|
target 'suixinkanTests' do
|
||||||
inherit! :search_paths
|
inherit! :search_paths
|
||||||
|
|||||||
@ -6,13 +6,11 @@ PODS:
|
|||||||
- AMapFoundation-NO-IDFA (>= 1.8.7)
|
- AMapFoundation-NO-IDFA (>= 1.8.7)
|
||||||
- AMapSearch-NO-IDFA (9.7.5):
|
- AMapSearch-NO-IDFA (9.7.5):
|
||||||
- AMapFoundation-NO-IDFA (>= 1.8.0)
|
- AMapFoundation-NO-IDFA (>= 1.8.0)
|
||||||
- MJRefresh (3.7.9)
|
|
||||||
|
|
||||||
DEPENDENCIES:
|
DEPENDENCIES:
|
||||||
- AMap3DMap-NO-IDFA (~> 11.1)
|
- AMap3DMap-NO-IDFA (~> 11.1)
|
||||||
- AMapLocation-NO-IDFA (~> 2.11)
|
- AMapLocation-NO-IDFA (~> 2.11)
|
||||||
- AMapSearch-NO-IDFA (~> 9.7)
|
- AMapSearch-NO-IDFA (~> 9.7)
|
||||||
- MJRefresh (~> 3.7)
|
|
||||||
|
|
||||||
SPEC REPOS:
|
SPEC REPOS:
|
||||||
trunk:
|
trunk:
|
||||||
@ -20,15 +18,13 @@ SPEC REPOS:
|
|||||||
- AMapFoundation-NO-IDFA
|
- AMapFoundation-NO-IDFA
|
||||||
- AMapLocation-NO-IDFA
|
- AMapLocation-NO-IDFA
|
||||||
- AMapSearch-NO-IDFA
|
- AMapSearch-NO-IDFA
|
||||||
- MJRefresh
|
|
||||||
|
|
||||||
SPEC CHECKSUMS:
|
SPEC CHECKSUMS:
|
||||||
AMap3DMap-NO-IDFA: 393a24abb0451fed2daa4316c8d3d356a395f2be
|
AMap3DMap-NO-IDFA: 393a24abb0451fed2daa4316c8d3d356a395f2be
|
||||||
AMapFoundation-NO-IDFA: f48acbf6e74913dc6744581053f7d984f2432850
|
AMapFoundation-NO-IDFA: f48acbf6e74913dc6744581053f7d984f2432850
|
||||||
AMapLocation-NO-IDFA: 0fa6e7d5e42e10253f4437424d98966f53760862
|
AMapLocation-NO-IDFA: 0fa6e7d5e42e10253f4437424d98966f53760862
|
||||||
AMapSearch-NO-IDFA: 8e9d104032990a3b0cab66afb535299887c61047
|
AMapSearch-NO-IDFA: 8e9d104032990a3b0cab66afb535299887c61047
|
||||||
MJRefresh: ff9e531227924c84ce459338414550a05d2aea78
|
|
||||||
|
|
||||||
PODFILE CHECKSUM: dd39a238c7d1f1de8b61bcb07e20911bedae96b7
|
PODFILE CHECKSUM: baa972253fcebc312545f7592c48cbba632f1907
|
||||||
|
|
||||||
COCOAPODS: 1.16.2
|
COCOAPODS: 1.16.2
|
||||||
|
|||||||
19
Pods/MJRefresh/LICENSE
generated
19
Pods/MJRefresh/LICENSE
generated
@ -1,19 +0,0 @@
|
|||||||
Copyright (c) 2013-2015 MJRefresh (https://github.com/CoderMJLee/MJRefresh)
|
|
||||||
|
|
||||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
||||||
of this software and associated documentation files (the "Software"), to deal
|
|
||||||
in the Software without restriction, including without limitation the rights
|
|
||||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
||||||
copies of the Software, and to permit persons to whom the Software is
|
|
||||||
furnished to do so, subject to the following conditions:
|
|
||||||
|
|
||||||
The above copyright notice and this permission notice shall be included in
|
|
||||||
all copies or substantial portions of the Software.
|
|
||||||
|
|
||||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
||||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
||||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
||||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
||||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
||||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
|
||||||
THE SOFTWARE.
|
|
||||||
34
Pods/MJRefresh/MJRefresh/Base/MJRefreshAutoFooter.h
generated
34
Pods/MJRefresh/MJRefresh/Base/MJRefreshAutoFooter.h
generated
@ -1,34 +0,0 @@
|
|||||||
//
|
|
||||||
// MJRefreshAutoFooter.h
|
|
||||||
// MJRefresh
|
|
||||||
//
|
|
||||||
// Created by MJ Lee on 15/4/24.
|
|
||||||
// Copyright (c) 2015年 小码哥. All rights reserved.
|
|
||||||
//
|
|
||||||
|
|
||||||
#if __has_include(<MJRefresh/MJRefreshFooter.h>)
|
|
||||||
#import <MJRefresh/MJRefreshFooter.h>
|
|
||||||
#else
|
|
||||||
#import "MJRefreshFooter.h"
|
|
||||||
#endif
|
|
||||||
|
|
||||||
NS_ASSUME_NONNULL_BEGIN
|
|
||||||
|
|
||||||
@interface MJRefreshAutoFooter : MJRefreshFooter
|
|
||||||
/** 是否自动刷新(默认为YES) */
|
|
||||||
@property (assign, nonatomic, getter=isAutomaticallyRefresh) BOOL automaticallyRefresh;
|
|
||||||
|
|
||||||
/** 当底部控件出现多少时就自动刷新(默认为1.0,也就是底部控件完全出现时,才会自动刷新) */
|
|
||||||
@property (assign, nonatomic) CGFloat appearencePercentTriggerAutoRefresh MJRefreshDeprecated("请使用triggerAutomaticallyRefreshPercent属性");
|
|
||||||
|
|
||||||
/** 当底部控件出现多少时就自动刷新(默认为1.0,也就是底部控件完全出现时,才会自动刷新) */
|
|
||||||
@property (assign, nonatomic) CGFloat triggerAutomaticallyRefreshPercent;
|
|
||||||
|
|
||||||
/** 自动触发次数, 默认为 1, 仅在拖拽 ScrollView 时才生效,
|
|
||||||
|
|
||||||
如果为 -1, 则为无限触发
|
|
||||||
*/
|
|
||||||
@property (nonatomic) NSInteger autoTriggerTimes;
|
|
||||||
@end
|
|
||||||
|
|
||||||
NS_ASSUME_NONNULL_END
|
|
||||||
216
Pods/MJRefresh/MJRefresh/Base/MJRefreshAutoFooter.m
generated
216
Pods/MJRefresh/MJRefresh/Base/MJRefreshAutoFooter.m
generated
@ -1,216 +0,0 @@
|
|||||||
//
|
|
||||||
// MJRefreshAutoFooter.m
|
|
||||||
// MJRefresh
|
|
||||||
//
|
|
||||||
// Created by MJ Lee on 15/4/24.
|
|
||||||
// Copyright (c) 2015年 小码哥. All rights reserved.
|
|
||||||
//
|
|
||||||
|
|
||||||
#import "MJRefreshAutoFooter.h"
|
|
||||||
#import "NSBundle+MJRefresh.h"
|
|
||||||
#import "UIView+MJExtension.h"
|
|
||||||
#import "UIScrollView+MJExtension.h"
|
|
||||||
#import "UIScrollView+MJRefresh.h"
|
|
||||||
|
|
||||||
@interface MJRefreshAutoFooter()
|
|
||||||
/** 一个新的拖拽 */
|
|
||||||
@property (nonatomic) BOOL triggerByDrag;
|
|
||||||
@property (nonatomic) NSInteger leftTriggerTimes;
|
|
||||||
@end
|
|
||||||
|
|
||||||
@implementation MJRefreshAutoFooter
|
|
||||||
|
|
||||||
#pragma mark - 初始化
|
|
||||||
- (void)willMoveToSuperview:(UIView *)newSuperview
|
|
||||||
{
|
|
||||||
[super willMoveToSuperview:newSuperview];
|
|
||||||
|
|
||||||
if (newSuperview) { // 新的父控件
|
|
||||||
if (self.hidden == NO) {
|
|
||||||
self.scrollView.mj_insetB += self.mj_h;
|
|
||||||
}
|
|
||||||
|
|
||||||
// 设置位置
|
|
||||||
self.mj_y = _scrollView.mj_contentH + self.ignoredScrollViewContentInsetBottom;
|
|
||||||
} else { // 被移除了
|
|
||||||
if (self.hidden == NO) {
|
|
||||||
self.scrollView.mj_insetB -= self.mj_h;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#pragma mark - 过期方法
|
|
||||||
- (void)setAppearencePercentTriggerAutoRefresh:(CGFloat)appearencePercentTriggerAutoRefresh
|
|
||||||
{
|
|
||||||
self.triggerAutomaticallyRefreshPercent = appearencePercentTriggerAutoRefresh;
|
|
||||||
}
|
|
||||||
|
|
||||||
- (CGFloat)appearencePercentTriggerAutoRefresh
|
|
||||||
{
|
|
||||||
return self.triggerAutomaticallyRefreshPercent;
|
|
||||||
}
|
|
||||||
|
|
||||||
#pragma mark - 实现父类的方法
|
|
||||||
- (void)prepare
|
|
||||||
{
|
|
||||||
[super prepare];
|
|
||||||
|
|
||||||
// 默认底部控件100%出现时才会自动刷新
|
|
||||||
self.triggerAutomaticallyRefreshPercent = 1.0;
|
|
||||||
|
|
||||||
// 设置为默认状态
|
|
||||||
self.automaticallyRefresh = YES;
|
|
||||||
|
|
||||||
self.autoTriggerTimes = 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
- (void)scrollViewContentSizeDidChange:(NSDictionary *)change
|
|
||||||
{
|
|
||||||
[super scrollViewContentSizeDidChange:change];
|
|
||||||
|
|
||||||
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) {
|
|
||||||
self.mj_y = y;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
- (void)scrollViewContentOffsetDidChange:(NSDictionary *)change
|
|
||||||
{
|
|
||||||
[super scrollViewContentOffsetDidChange:change];
|
|
||||||
|
|
||||||
if (self.state != MJRefreshStateIdle || !self.automaticallyRefresh || self.mj_y == 0) return;
|
|
||||||
|
|
||||||
if (_scrollView.mj_insetT + _scrollView.mj_contentH > _scrollView.mj_h) { // 内容超过一个屏幕
|
|
||||||
// 这里的_scrollView.mj_contentH替换掉self.mj_y更为合理
|
|
||||||
if (_scrollView.mj_offsetY >= _scrollView.mj_contentH - _scrollView.mj_h + self.mj_h * self.triggerAutomaticallyRefreshPercent + _scrollView.mj_insetB - self.mj_h) {
|
|
||||||
// 防止手松开时连续调用
|
|
||||||
CGPoint old = [change[@"old"] CGPointValue];
|
|
||||||
CGPoint new = [change[@"new"] CGPointValue];
|
|
||||||
if (new.y <= old.y) return;
|
|
||||||
|
|
||||||
if (_scrollView.isDragging) {
|
|
||||||
self.triggerByDrag = YES;
|
|
||||||
}
|
|
||||||
// 当底部刷新控件完全出现时,才刷新
|
|
||||||
[self beginRefreshing];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
- (void)scrollViewPanStateDidChange:(NSDictionary *)change
|
|
||||||
{
|
|
||||||
[super scrollViewPanStateDidChange:change];
|
|
||||||
|
|
||||||
if (self.state != MJRefreshStateIdle) return;
|
|
||||||
|
|
||||||
UIGestureRecognizerState panState = _scrollView.panGestureRecognizer.state;
|
|
||||||
|
|
||||||
switch (panState) {
|
|
||||||
// 手松开
|
|
||||||
case UIGestureRecognizerStateEnded: {
|
|
||||||
if (_scrollView.mj_insetT + _scrollView.mj_contentH <= _scrollView.mj_h) { // 不够一个屏幕
|
|
||||||
if (_scrollView.mj_offsetY >= - _scrollView.mj_insetT) { // 向上拽
|
|
||||||
self.triggerByDrag = YES;
|
|
||||||
[self beginRefreshing];
|
|
||||||
}
|
|
||||||
} else { // 超出一个屏幕
|
|
||||||
if (_scrollView.mj_offsetY >= _scrollView.mj_contentH + _scrollView.mj_insetB - _scrollView.mj_h) {
|
|
||||||
self.triggerByDrag = YES;
|
|
||||||
[self beginRefreshing];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
|
|
||||||
case UIGestureRecognizerStateBegan: {
|
|
||||||
[self resetTriggerTimes];
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
- (BOOL)unlimitedTrigger {
|
|
||||||
return self.leftTriggerTimes == -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
- (void)beginRefreshing
|
|
||||||
{
|
|
||||||
if (self.triggerByDrag && self.leftTriggerTimes <= 0 && !self.unlimitedTrigger) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
[super beginRefreshing];
|
|
||||||
}
|
|
||||||
|
|
||||||
- (void)setState:(MJRefreshState)state
|
|
||||||
{
|
|
||||||
MJRefreshCheckState
|
|
||||||
|
|
||||||
if (state == MJRefreshStateRefreshing) {
|
|
||||||
[self executeRefreshingCallback];
|
|
||||||
} else if (state == MJRefreshStateNoMoreData || state == MJRefreshStateIdle) {
|
|
||||||
if (self.triggerByDrag) {
|
|
||||||
if (!self.unlimitedTrigger) {
|
|
||||||
self.leftTriggerTimes -= 1;
|
|
||||||
}
|
|
||||||
self.triggerByDrag = NO;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (MJRefreshStateRefreshing == oldState) {
|
|
||||||
if (self.scrollView.pagingEnabled) {
|
|
||||||
CGPoint offset = self.scrollView.contentOffset;
|
|
||||||
offset.y -= self.scrollView.mj_insetB;
|
|
||||||
[UIView animateWithDuration:self.slowAnimationDuration animations:^{
|
|
||||||
self.scrollView.contentOffset = offset;
|
|
||||||
|
|
||||||
if (self.endRefreshingAnimationBeginAction) {
|
|
||||||
self.endRefreshingAnimationBeginAction();
|
|
||||||
}
|
|
||||||
} completion:^(BOOL finished) {
|
|
||||||
if (self.endRefreshingCompletionBlock) {
|
|
||||||
self.endRefreshingCompletionBlock();
|
|
||||||
}
|
|
||||||
}];
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (self.endRefreshingCompletionBlock) {
|
|
||||||
self.endRefreshingCompletionBlock();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
- (void)resetTriggerTimes {
|
|
||||||
self.leftTriggerTimes = self.autoTriggerTimes;
|
|
||||||
}
|
|
||||||
|
|
||||||
- (void)setHidden:(BOOL)hidden
|
|
||||||
{
|
|
||||||
BOOL lastHidden = self.isHidden;
|
|
||||||
|
|
||||||
[super setHidden:hidden];
|
|
||||||
|
|
||||||
if (!lastHidden && hidden) {
|
|
||||||
self.state = MJRefreshStateIdle;
|
|
||||||
|
|
||||||
self.scrollView.mj_insetB -= self.mj_h;
|
|
||||||
} else if (lastHidden && !hidden) {
|
|
||||||
self.scrollView.mj_insetB += self.mj_h;
|
|
||||||
|
|
||||||
// 设置位置
|
|
||||||
self.mj_y = _scrollView.mj_contentH + self.ignoredScrollViewContentInsetBottom;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
- (void)setAutoTriggerTimes:(NSInteger)autoTriggerTimes {
|
|
||||||
_autoTriggerTimes = autoTriggerTimes;
|
|
||||||
self.leftTriggerTimes = autoTriggerTimes;
|
|
||||||
}
|
|
||||||
@end
|
|
||||||
21
Pods/MJRefresh/MJRefresh/Base/MJRefreshBackFooter.h
generated
21
Pods/MJRefresh/MJRefresh/Base/MJRefreshBackFooter.h
generated
@ -1,21 +0,0 @@
|
|||||||
//
|
|
||||||
// MJRefreshBackFooter.h
|
|
||||||
// MJRefresh
|
|
||||||
//
|
|
||||||
// Created by MJ Lee on 15/4/24.
|
|
||||||
// Copyright (c) 2015年 小码哥. All rights reserved.
|
|
||||||
//
|
|
||||||
|
|
||||||
#if __has_include(<MJRefresh/MJRefreshFooter.h>)
|
|
||||||
#import <MJRefresh/MJRefreshFooter.h>
|
|
||||||
#else
|
|
||||||
#import "MJRefreshFooter.h"
|
|
||||||
#endif
|
|
||||||
|
|
||||||
NS_ASSUME_NONNULL_BEGIN
|
|
||||||
|
|
||||||
@interface MJRefreshBackFooter : MJRefreshFooter
|
|
||||||
|
|
||||||
@end
|
|
||||||
|
|
||||||
NS_ASSUME_NONNULL_END
|
|
||||||
158
Pods/MJRefresh/MJRefresh/Base/MJRefreshBackFooter.m
generated
158
Pods/MJRefresh/MJRefresh/Base/MJRefreshBackFooter.m
generated
@ -1,158 +0,0 @@
|
|||||||
//
|
|
||||||
// MJRefreshBackFooter.m
|
|
||||||
// MJRefresh
|
|
||||||
//
|
|
||||||
// Created by MJ Lee on 15/4/24.
|
|
||||||
// Copyright (c) 2015年 小码哥. All rights reserved.
|
|
||||||
//
|
|
||||||
|
|
||||||
#import "MJRefreshBackFooter.h"
|
|
||||||
#import "NSBundle+MJRefresh.h"
|
|
||||||
#import "UIView+MJExtension.h"
|
|
||||||
#import "UIScrollView+MJExtension.h"
|
|
||||||
#import "UIScrollView+MJRefresh.h"
|
|
||||||
|
|
||||||
@interface MJRefreshBackFooter()
|
|
||||||
@property (assign, nonatomic) NSInteger lastRefreshCount;
|
|
||||||
@property (assign, nonatomic) CGFloat lastBottomDelta;
|
|
||||||
@end
|
|
||||||
|
|
||||||
@implementation MJRefreshBackFooter
|
|
||||||
|
|
||||||
#pragma mark - 初始化
|
|
||||||
- (void)willMoveToSuperview:(UIView *)newSuperview
|
|
||||||
{
|
|
||||||
[super willMoveToSuperview:newSuperview];
|
|
||||||
|
|
||||||
[self scrollViewContentSizeDidChange:nil];
|
|
||||||
}
|
|
||||||
|
|
||||||
#pragma mark - 实现父类的方法
|
|
||||||
- (void)scrollViewContentOffsetDidChange:(NSDictionary *)change
|
|
||||||
{
|
|
||||||
[super scrollViewContentOffsetDidChange:change];
|
|
||||||
|
|
||||||
// 如果正在刷新,直接返回
|
|
||||||
if (self.state == MJRefreshStateRefreshing) return;
|
|
||||||
|
|
||||||
_scrollViewOriginalInset = self.scrollView.mj_inset;
|
|
||||||
|
|
||||||
// 当前的contentOffset
|
|
||||||
CGFloat currentOffsetY = self.scrollView.mj_offsetY;
|
|
||||||
// 尾部控件刚好出现的offsetY
|
|
||||||
CGFloat happenOffsetY = [self happenOffsetY];
|
|
||||||
// 如果是向下滚动到看不见尾部控件,直接返回
|
|
||||||
if (currentOffsetY <= happenOffsetY) return;
|
|
||||||
|
|
||||||
CGFloat pullingPercent = (currentOffsetY - happenOffsetY) / self.mj_h;
|
|
||||||
|
|
||||||
// 如果已全部加载,仅设置pullingPercent,然后返回
|
|
||||||
if (self.state == MJRefreshStateNoMoreData) {
|
|
||||||
self.pullingPercent = pullingPercent;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (self.scrollView.isDragging) {
|
|
||||||
self.pullingPercent = pullingPercent;
|
|
||||||
// 普通 和 即将刷新 的临界点
|
|
||||||
CGFloat normal2pullingOffsetY = happenOffsetY + self.mj_h;
|
|
||||||
|
|
||||||
if (self.state == MJRefreshStateIdle && currentOffsetY > normal2pullingOffsetY) {
|
|
||||||
// 转为即将刷新状态
|
|
||||||
self.state = MJRefreshStatePulling;
|
|
||||||
} else if (self.state == MJRefreshStatePulling && currentOffsetY <= normal2pullingOffsetY) {
|
|
||||||
// 转为普通状态
|
|
||||||
self.state = MJRefreshStateIdle;
|
|
||||||
}
|
|
||||||
} else if (self.state == MJRefreshStatePulling) {// 即将刷新 && 手松开
|
|
||||||
// 开始刷新
|
|
||||||
[self beginRefreshing];
|
|
||||||
} else if (pullingPercent < 1) {
|
|
||||||
self.pullingPercent = pullingPercent;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
- (void)scrollViewContentSizeDidChange:(NSDictionary *)change
|
|
||||||
{
|
|
||||||
[super scrollViewContentSizeDidChange:change];
|
|
||||||
|
|
||||||
CGSize size = [change[NSKeyValueChangeNewKey] CGSizeValue];
|
|
||||||
CGFloat contentHeight = size.height == 0 ? self.scrollView.mj_contentH : size.height;
|
|
||||||
// 内容的高度
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
- (void)setState:(MJRefreshState)state
|
|
||||||
{
|
|
||||||
MJRefreshCheckState
|
|
||||||
|
|
||||||
// 根据状态来设置属性
|
|
||||||
if (state == MJRefreshStateNoMoreData || state == MJRefreshStateIdle) {
|
|
||||||
// 刷新完毕
|
|
||||||
if (MJRefreshStateRefreshing == oldState) {
|
|
||||||
[UIView animateWithDuration:self.slowAnimationDuration animations:^{
|
|
||||||
if (self.endRefreshingAnimationBeginAction) {
|
|
||||||
self.endRefreshingAnimationBeginAction();
|
|
||||||
}
|
|
||||||
|
|
||||||
self.scrollView.mj_insetB -= self.lastBottomDelta;
|
|
||||||
// 自动调整透明度
|
|
||||||
if (self.isAutomaticallyChangeAlpha) self.alpha = 0.0;
|
|
||||||
} completion:^(BOOL finished) {
|
|
||||||
self.pullingPercent = 0.0;
|
|
||||||
|
|
||||||
if (self.endRefreshingCompletionBlock) {
|
|
||||||
self.endRefreshingCompletionBlock();
|
|
||||||
}
|
|
||||||
}];
|
|
||||||
}
|
|
||||||
|
|
||||||
CGFloat deltaH = [self heightForContentBreakView];
|
|
||||||
// 刚刷新完毕
|
|
||||||
if (MJRefreshStateRefreshing == oldState && deltaH > 0 && self.scrollView.mj_totalDataCount != self.lastRefreshCount) {
|
|
||||||
self.scrollView.mj_offsetY = self.scrollView.mj_offsetY;
|
|
||||||
}
|
|
||||||
} else if (state == MJRefreshStateRefreshing) {
|
|
||||||
// 记录刷新前的数量
|
|
||||||
self.lastRefreshCount = self.scrollView.mj_totalDataCount;
|
|
||||||
|
|
||||||
[UIView animateWithDuration:self.fastAnimationDuration animations:^{
|
|
||||||
CGFloat bottom = self.mj_h + self.scrollViewOriginalInset.bottom;
|
|
||||||
CGFloat deltaH = [self heightForContentBreakView];
|
|
||||||
if (deltaH < 0) { // 如果内容高度小于view的高度
|
|
||||||
bottom -= deltaH;
|
|
||||||
}
|
|
||||||
self.lastBottomDelta = bottom - self.scrollView.mj_insetB;
|
|
||||||
self.scrollView.mj_insetB = bottom;
|
|
||||||
self.scrollView.mj_offsetY = [self happenOffsetY] + self.mj_h;
|
|
||||||
} completion:^(BOOL finished) {
|
|
||||||
[self executeRefreshingCallback];
|
|
||||||
}];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#pragma mark - 私有方法
|
|
||||||
#pragma mark 获得scrollView的内容 超出 view 的高度
|
|
||||||
- (CGFloat)heightForContentBreakView
|
|
||||||
{
|
|
||||||
CGFloat h = self.scrollView.frame.size.height - self.scrollViewOriginalInset.bottom - self.scrollViewOriginalInset.top;
|
|
||||||
return self.scrollView.contentSize.height - h;
|
|
||||||
}
|
|
||||||
|
|
||||||
#pragma mark 刚好看到上拉刷新控件时的contentOffset.y
|
|
||||||
- (CGFloat)happenOffsetY
|
|
||||||
{
|
|
||||||
CGFloat deltaH = [self heightForContentBreakView];
|
|
||||||
if (deltaH > 0) {
|
|
||||||
return deltaH - self.scrollViewOriginalInset.top;
|
|
||||||
} else {
|
|
||||||
return - self.scrollViewOriginalInset.top;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@end
|
|
||||||
151
Pods/MJRefresh/MJRefresh/Base/MJRefreshComponent.h
generated
151
Pods/MJRefresh/MJRefresh/Base/MJRefreshComponent.h
generated
@ -1,151 +0,0 @@
|
|||||||
// 代码地址: https://github.com/CoderMJLee/MJRefresh
|
|
||||||
// MJRefreshComponent.h
|
|
||||||
// MJRefresh
|
|
||||||
//
|
|
||||||
// Created by MJ Lee on 15/3/4.
|
|
||||||
// Copyright (c) 2015年 小码哥. All rights reserved.
|
|
||||||
// 刷新控件的基类
|
|
||||||
|
|
||||||
#import <UIKit/UIKit.h>
|
|
||||||
#if __has_include(<MJRefresh/MJRefreshConst.h>)
|
|
||||||
#import <MJRefresh/MJRefreshConst.h>
|
|
||||||
#else
|
|
||||||
#import "MJRefreshConst.h"
|
|
||||||
#endif
|
|
||||||
|
|
||||||
NS_ASSUME_NONNULL_BEGIN
|
|
||||||
|
|
||||||
/** 刷新控件的状态 */
|
|
||||||
typedef NS_ENUM(NSInteger, MJRefreshState) {
|
|
||||||
/** 普通闲置状态 */
|
|
||||||
MJRefreshStateIdle = 1,
|
|
||||||
/** 松开就可以进行刷新的状态 */
|
|
||||||
MJRefreshStatePulling,
|
|
||||||
/** 正在刷新中的状态 */
|
|
||||||
MJRefreshStateRefreshing,
|
|
||||||
/** 即将刷新的状态 */
|
|
||||||
MJRefreshStateWillRefresh,
|
|
||||||
/** 所有数据加载完毕,没有更多的数据了 */
|
|
||||||
MJRefreshStateNoMoreData
|
|
||||||
};
|
|
||||||
|
|
||||||
/** 进入刷新状态的回调 */
|
|
||||||
typedef void (^MJRefreshComponentRefreshingBlock)(void) MJRefreshDeprecated("first deprecated in 3.3.0 - Use `MJRefreshComponentAction` instead");
|
|
||||||
/** 开始刷新后的回调(进入刷新状态后的回调) */
|
|
||||||
typedef void (^MJRefreshComponentBeginRefreshingCompletionBlock)(void) MJRefreshDeprecated("first deprecated in 3.3.0 - Use `MJRefreshComponentAction` instead");
|
|
||||||
/** 结束刷新后的回调 */
|
|
||||||
typedef void (^MJRefreshComponentEndRefreshingCompletionBlock)(void) MJRefreshDeprecated("first deprecated in 3.3.0 - Use `MJRefreshComponentAction` instead");
|
|
||||||
|
|
||||||
/** 刷新用到的回调类型 */
|
|
||||||
typedef void (^MJRefreshComponentAction)(void);
|
|
||||||
|
|
||||||
/** 刷新控件的基类 */
|
|
||||||
@interface MJRefreshComponent : UIView
|
|
||||||
{
|
|
||||||
/** 记录scrollView刚开始的inset */
|
|
||||||
UIEdgeInsets _scrollViewOriginalInset;
|
|
||||||
/** 父控件 */
|
|
||||||
__weak UIScrollView *_scrollView;
|
|
||||||
}
|
|
||||||
|
|
||||||
#pragma mark - 刷新动画时间控制
|
|
||||||
/** 快速动画时间(一般用在刷新开始的回弹动画), 默认 0.25 */
|
|
||||||
@property (nonatomic) NSTimeInterval fastAnimationDuration;
|
|
||||||
/** 慢速动画时间(一般用在刷新结束后的回弹动画), 默认 0.4*/
|
|
||||||
@property (nonatomic) NSTimeInterval slowAnimationDuration;
|
|
||||||
/** 关闭全部默认动画效果, 可以简单粗暴地解决 CollectionView 的回弹动画 bug */
|
|
||||||
- (instancetype)setAnimationDisabled;
|
|
||||||
|
|
||||||
#pragma mark - 刷新回调
|
|
||||||
/** 正在刷新的回调 */
|
|
||||||
@property (copy, nonatomic, nullable) MJRefreshComponentAction refreshingBlock;
|
|
||||||
/** 设置回调对象和回调方法 */
|
|
||||||
- (void)setRefreshingTarget:(id)target refreshingAction:(SEL)action;
|
|
||||||
|
|
||||||
/** 回调对象 */
|
|
||||||
@property (weak, nonatomic) id refreshingTarget;
|
|
||||||
/** 回调方法 */
|
|
||||||
@property (assign, nonatomic) SEL refreshingAction;
|
|
||||||
/** 触发回调(交给子类去调用) */
|
|
||||||
- (void)executeRefreshingCallback;
|
|
||||||
|
|
||||||
#pragma mark - 刷新状态控制
|
|
||||||
/** 进入刷新状态 */
|
|
||||||
- (void)beginRefreshing;
|
|
||||||
- (void)beginRefreshingWithCompletionBlock:(void (^)(void))completionBlock;
|
|
||||||
/** 开始刷新后的回调(进入刷新状态后的回调) */
|
|
||||||
@property (copy, nonatomic, nullable) MJRefreshComponentAction beginRefreshingCompletionBlock;
|
|
||||||
/** 带动画的结束刷新的回调 */
|
|
||||||
@property (copy, nonatomic, nullable) MJRefreshComponentAction endRefreshingAnimateCompletionBlock MJRefreshDeprecated("first deprecated in 3.3.0 - Use `endRefreshingAnimationBeginAction` instead");
|
|
||||||
@property (copy, nonatomic, nullable) MJRefreshComponentAction endRefreshingAnimationBeginAction;
|
|
||||||
/** 结束刷新的回调 */
|
|
||||||
@property (copy, nonatomic, nullable) MJRefreshComponentAction endRefreshingCompletionBlock;
|
|
||||||
/** 结束刷新状态 */
|
|
||||||
- (void)endRefreshing;
|
|
||||||
- (void)endRefreshingWithCompletionBlock:(void (^)(void))completionBlock;
|
|
||||||
/** 是否正在刷新 */
|
|
||||||
@property (assign, nonatomic, readonly, getter=isRefreshing) BOOL refreshing;
|
|
||||||
|
|
||||||
/** 刷新状态 一般交给子类内部实现 */
|
|
||||||
@property (assign, nonatomic) MJRefreshState state;
|
|
||||||
|
|
||||||
#pragma mark - 交给子类去访问
|
|
||||||
/** 记录scrollView刚开始的inset */
|
|
||||||
@property (assign, nonatomic, readonly) UIEdgeInsets scrollViewOriginalInset;
|
|
||||||
/** 父控件 */
|
|
||||||
@property (weak, nonatomic, readonly) UIScrollView *scrollView;
|
|
||||||
|
|
||||||
#pragma mark - 交给子类们去实现
|
|
||||||
/** 初始化 */
|
|
||||||
- (void)prepare NS_REQUIRES_SUPER;
|
|
||||||
/** 摆放子控件frame */
|
|
||||||
- (void)placeSubviews NS_REQUIRES_SUPER;
|
|
||||||
/** 当scrollView的contentOffset发生改变的时候调用 */
|
|
||||||
- (void)scrollViewContentOffsetDidChange:(nullable NSDictionary *)change NS_REQUIRES_SUPER;
|
|
||||||
/** 当scrollView的contentSize发生改变的时候调用 */
|
|
||||||
- (void)scrollViewContentSizeDidChange:(nullable NSDictionary *)change NS_REQUIRES_SUPER;
|
|
||||||
/** 当scrollView的拖拽状态发生改变的时候调用 */
|
|
||||||
- (void)scrollViewPanStateDidChange:(nullable NSDictionary *)change NS_REQUIRES_SUPER;
|
|
||||||
|
|
||||||
/** 多语言配置 language 发生变化时调用
|
|
||||||
|
|
||||||
`MJRefreshConfig.defaultConfig.language` 发生改变时调用.
|
|
||||||
|
|
||||||
⚠️ 父类会调用 `placeSubviews` 方法, 请勿在 placeSubviews 中调用本方法, 造成死循环. 子类在需要重新布局时, 在配置完修改后, 最后再调用 super 方法, 否则可能导致配置修改后, 定位先于修改执行.
|
|
||||||
*/
|
|
||||||
- (void)i18nDidChange NS_REQUIRES_SUPER;
|
|
||||||
|
|
||||||
#pragma mark - 其他
|
|
||||||
/** 拉拽的百分比(交给子类重写) */
|
|
||||||
@property (assign, nonatomic) CGFloat pullingPercent;
|
|
||||||
/** 根据拖拽比例自动切换透明度 */
|
|
||||||
@property (assign, nonatomic, getter=isAutoChangeAlpha) BOOL autoChangeAlpha MJRefreshDeprecated("请使用automaticallyChangeAlpha属性");
|
|
||||||
/** 根据拖拽比例自动切换透明度 */
|
|
||||||
@property (assign, nonatomic, getter=isAutomaticallyChangeAlpha) BOOL automaticallyChangeAlpha;
|
|
||||||
@end
|
|
||||||
|
|
||||||
@interface UILabel(MJRefresh)
|
|
||||||
+ (instancetype)mj_label;
|
|
||||||
- (CGFloat)mj_textWidth;
|
|
||||||
@end
|
|
||||||
|
|
||||||
@interface MJRefreshComponent (ChainingGrammar)
|
|
||||||
|
|
||||||
#pragma mark - <<< 为 Swift 扩展链式语法 >>> -
|
|
||||||
/// 自动变化透明度
|
|
||||||
- (instancetype)autoChangeTransparency:(BOOL)isAutoChange;
|
|
||||||
/// 刷新开始后立即调用的回调
|
|
||||||
- (instancetype)afterBeginningAction:(MJRefreshComponentAction)action;
|
|
||||||
/// 刷新动画开始后立即调用的回调
|
|
||||||
- (instancetype)endingAnimationBeginningAction:(MJRefreshComponentAction)action;
|
|
||||||
/// 刷新结束后立即调用的回调
|
|
||||||
- (instancetype)afterEndingAction:(MJRefreshComponentAction)action;
|
|
||||||
|
|
||||||
|
|
||||||
/// 需要子类必须实现
|
|
||||||
/// @param scrollView 赋值给的 ScrollView 的 Header/Footer/Trailer
|
|
||||||
- (instancetype)linkTo:(UIScrollView *)scrollView;
|
|
||||||
|
|
||||||
@end
|
|
||||||
|
|
||||||
NS_ASSUME_NONNULL_END
|
|
||||||
323
Pods/MJRefresh/MJRefresh/Base/MJRefreshComponent.m
generated
323
Pods/MJRefresh/MJRefresh/Base/MJRefreshComponent.m
generated
@ -1,323 +0,0 @@
|
|||||||
// 代码地址: https://github.com/CoderMJLee/MJRefresh
|
|
||||||
// MJRefreshComponent.m
|
|
||||||
// MJRefresh
|
|
||||||
//
|
|
||||||
// Created by MJ Lee on 15/3/4.
|
|
||||||
// Copyright (c) 2015年 小码哥. All rights reserved.
|
|
||||||
//
|
|
||||||
|
|
||||||
#import "MJRefreshComponent.h"
|
|
||||||
#import "MJRefreshConst.h"
|
|
||||||
#import "MJRefreshConfig.h"
|
|
||||||
#import "UIView+MJExtension.h"
|
|
||||||
#import "UIScrollView+MJExtension.h"
|
|
||||||
#import "UIScrollView+MJRefresh.h"
|
|
||||||
#import "NSBundle+MJRefresh.h"
|
|
||||||
|
|
||||||
@interface MJRefreshComponent()
|
|
||||||
@property (strong, nonatomic) UIPanGestureRecognizer *pan;
|
|
||||||
@end
|
|
||||||
|
|
||||||
@implementation MJRefreshComponent
|
|
||||||
#pragma mark - 初始化
|
|
||||||
- (instancetype)initWithFrame:(CGRect)frame
|
|
||||||
{
|
|
||||||
if (self = [super initWithFrame:frame]) {
|
|
||||||
// 准备工作
|
|
||||||
[self prepare];
|
|
||||||
|
|
||||||
// 默认是普通状态
|
|
||||||
self.state = MJRefreshStateIdle;
|
|
||||||
self.fastAnimationDuration = 0.25;
|
|
||||||
self.slowAnimationDuration = 0.4;
|
|
||||||
}
|
|
||||||
return self;
|
|
||||||
}
|
|
||||||
|
|
||||||
- (void)prepare
|
|
||||||
{
|
|
||||||
// 基本属性
|
|
||||||
self.autoresizingMask = UIViewAutoresizingFlexibleWidth;
|
|
||||||
self.backgroundColor = [UIColor clearColor];
|
|
||||||
}
|
|
||||||
|
|
||||||
- (void)layoutSubviews
|
|
||||||
{
|
|
||||||
[self placeSubviews];
|
|
||||||
|
|
||||||
[super layoutSubviews];
|
|
||||||
}
|
|
||||||
|
|
||||||
- (void)placeSubviews{}
|
|
||||||
|
|
||||||
- (void)willMoveToSuperview:(UIView *)newSuperview
|
|
||||||
{
|
|
||||||
[super willMoveToSuperview:newSuperview];
|
|
||||||
|
|
||||||
// 如果不是UIScrollView,不做任何事情
|
|
||||||
if (newSuperview && ![newSuperview isKindOfClass:[UIScrollView class]]) return;
|
|
||||||
|
|
||||||
// 旧的父控件移除监听
|
|
||||||
[self removeObservers];
|
|
||||||
|
|
||||||
if (newSuperview) { // 新的父控件
|
|
||||||
// 记录UIScrollView
|
|
||||||
_scrollView = (UIScrollView *)newSuperview;
|
|
||||||
|
|
||||||
// 设置宽度
|
|
||||||
self.mj_w = _scrollView.mj_w;
|
|
||||||
// 设置位置
|
|
||||||
self.mj_x = -_scrollView.mj_insetL;
|
|
||||||
|
|
||||||
// 设置永远支持垂直弹簧效果
|
|
||||||
_scrollView.alwaysBounceVertical = YES;
|
|
||||||
// 记录UIScrollView最开始的contentInset
|
|
||||||
_scrollViewOriginalInset = _scrollView.mj_inset;
|
|
||||||
|
|
||||||
// 添加监听
|
|
||||||
[self addObservers];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
- (void)drawRect:(CGRect)rect
|
|
||||||
{
|
|
||||||
[super drawRect:rect];
|
|
||||||
|
|
||||||
if (self.state == MJRefreshStateWillRefresh) {
|
|
||||||
// 预防view还没显示出来就调用了beginRefreshing
|
|
||||||
self.state = MJRefreshStateRefreshing;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#pragma mark - KVO监听
|
|
||||||
- (void)addObservers
|
|
||||||
{
|
|
||||||
NSKeyValueObservingOptions options = NSKeyValueObservingOptionNew | NSKeyValueObservingOptionOld;
|
|
||||||
[self.scrollView addObserver:self forKeyPath:MJRefreshKeyPathContentOffset options:options context:nil];
|
|
||||||
[self.scrollView addObserver:self forKeyPath:MJRefreshKeyPathContentSize options:options context:nil];
|
|
||||||
self.pan = self.scrollView.panGestureRecognizer;
|
|
||||||
[self.pan addObserver:self forKeyPath:MJRefreshKeyPathPanState options:options context:nil];
|
|
||||||
|
|
||||||
[NSNotificationCenter.defaultCenter addObserver:self selector:@selector(i18nDidChange) name:MJRefreshDidChangeLanguageNotification object:MJRefreshConfig.defaultConfig];
|
|
||||||
}
|
|
||||||
|
|
||||||
- (void)removeObservers
|
|
||||||
{
|
|
||||||
[self.superview removeObserver:self forKeyPath:MJRefreshKeyPathContentOffset];
|
|
||||||
[self.superview removeObserver:self forKeyPath:MJRefreshKeyPathContentSize];
|
|
||||||
[self.pan removeObserver:self forKeyPath:MJRefreshKeyPathPanState];
|
|
||||||
self.pan = nil;
|
|
||||||
}
|
|
||||||
|
|
||||||
- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context
|
|
||||||
{
|
|
||||||
// 遇到这些情况就直接返回
|
|
||||||
if (!self.userInteractionEnabled) return;
|
|
||||||
|
|
||||||
// 这个就算看不见也需要处理
|
|
||||||
if ([keyPath isEqualToString:MJRefreshKeyPathContentSize]) {
|
|
||||||
[self scrollViewContentSizeDidChange:change];
|
|
||||||
}
|
|
||||||
|
|
||||||
// 看不见
|
|
||||||
if (self.hidden) return;
|
|
||||||
if ([keyPath isEqualToString:MJRefreshKeyPathContentOffset]) {
|
|
||||||
[self scrollViewContentOffsetDidChange:change];
|
|
||||||
} else if ([keyPath isEqualToString:MJRefreshKeyPathPanState]) {
|
|
||||||
[self scrollViewPanStateDidChange:change];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
- (void)scrollViewContentOffsetDidChange:(NSDictionary *)change{}
|
|
||||||
- (void)scrollViewContentSizeDidChange:(NSDictionary *)change{}
|
|
||||||
- (void)scrollViewPanStateDidChange:(NSDictionary *)change{}
|
|
||||||
|
|
||||||
- (void)i18nDidChange {
|
|
||||||
[self placeSubviews];
|
|
||||||
}
|
|
||||||
|
|
||||||
#pragma mark - 公共方法
|
|
||||||
#pragma mark 设置回调对象和回调方法
|
|
||||||
- (void)setRefreshingTarget:(id)target refreshingAction:(SEL)action
|
|
||||||
{
|
|
||||||
self.refreshingTarget = target;
|
|
||||||
self.refreshingAction = action;
|
|
||||||
}
|
|
||||||
|
|
||||||
- (void)setState:(MJRefreshState)state
|
|
||||||
{
|
|
||||||
_state = state;
|
|
||||||
|
|
||||||
// 加入主队列的目的是等setState:方法调用完毕、设置完文字后再去布局子控件
|
|
||||||
MJRefreshDispatchAsyncOnMainQueue([self setNeedsLayout];)
|
|
||||||
}
|
|
||||||
|
|
||||||
#pragma mark 进入刷新状态
|
|
||||||
- (void)beginRefreshing
|
|
||||||
{
|
|
||||||
[UIView animateWithDuration:self.fastAnimationDuration animations:^{
|
|
||||||
self.alpha = 1.0;
|
|
||||||
}];
|
|
||||||
self.pullingPercent = 1.0;
|
|
||||||
// 只要正在刷新,就完全显示
|
|
||||||
if (self.window) {
|
|
||||||
self.state = MJRefreshStateRefreshing;
|
|
||||||
} else {
|
|
||||||
// 预防正在刷新中时,调用本方法使得header inset回置失败
|
|
||||||
if (self.state != MJRefreshStateRefreshing) {
|
|
||||||
self.state = MJRefreshStateWillRefresh;
|
|
||||||
// 刷新(预防从另一个控制器回到这个控制器的情况,回来要重新刷新一下)
|
|
||||||
[self setNeedsDisplay];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
- (void)beginRefreshingWithCompletionBlock:(void (^)(void))completionBlock
|
|
||||||
{
|
|
||||||
self.beginRefreshingCompletionBlock = completionBlock;
|
|
||||||
|
|
||||||
[self beginRefreshing];
|
|
||||||
}
|
|
||||||
|
|
||||||
#pragma mark 结束刷新状态
|
|
||||||
- (void)endRefreshing
|
|
||||||
{
|
|
||||||
MJRefreshDispatchAsyncOnMainQueue(self.state = MJRefreshStateIdle;)
|
|
||||||
}
|
|
||||||
|
|
||||||
- (void)endRefreshingWithCompletionBlock:(void (^)(void))completionBlock
|
|
||||||
{
|
|
||||||
self.endRefreshingCompletionBlock = completionBlock;
|
|
||||||
|
|
||||||
[self endRefreshing];
|
|
||||||
}
|
|
||||||
|
|
||||||
#pragma mark 是否正在刷新
|
|
||||||
- (BOOL)isRefreshing
|
|
||||||
{
|
|
||||||
return self.state == MJRefreshStateRefreshing || self.state == MJRefreshStateWillRefresh;
|
|
||||||
}
|
|
||||||
|
|
||||||
#pragma mark 自动切换透明度
|
|
||||||
- (void)setAutoChangeAlpha:(BOOL)autoChangeAlpha
|
|
||||||
{
|
|
||||||
self.automaticallyChangeAlpha = autoChangeAlpha;
|
|
||||||
}
|
|
||||||
|
|
||||||
- (BOOL)isAutoChangeAlpha
|
|
||||||
{
|
|
||||||
return self.isAutomaticallyChangeAlpha;
|
|
||||||
}
|
|
||||||
|
|
||||||
- (void)setAutomaticallyChangeAlpha:(BOOL)automaticallyChangeAlpha
|
|
||||||
{
|
|
||||||
_automaticallyChangeAlpha = automaticallyChangeAlpha;
|
|
||||||
|
|
||||||
if (self.isRefreshing) return;
|
|
||||||
|
|
||||||
if (automaticallyChangeAlpha) {
|
|
||||||
self.alpha = self.pullingPercent;
|
|
||||||
} else {
|
|
||||||
self.alpha = 1.0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#pragma mark 根据拖拽进度设置透明度
|
|
||||||
- (void)setPullingPercent:(CGFloat)pullingPercent
|
|
||||||
{
|
|
||||||
_pullingPercent = pullingPercent;
|
|
||||||
|
|
||||||
if (self.isRefreshing) return;
|
|
||||||
|
|
||||||
if (self.isAutomaticallyChangeAlpha) {
|
|
||||||
self.alpha = pullingPercent;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#pragma mark - 内部方法
|
|
||||||
- (void)executeRefreshingCallback
|
|
||||||
{
|
|
||||||
if (self.refreshingBlock) {
|
|
||||||
self.refreshingBlock();
|
|
||||||
}
|
|
||||||
if ([self.refreshingTarget respondsToSelector:self.refreshingAction]) {
|
|
||||||
MJRefreshMsgSend(MJRefreshMsgTarget(self.refreshingTarget), self.refreshingAction, self);
|
|
||||||
}
|
|
||||||
if (self.beginRefreshingCompletionBlock) {
|
|
||||||
self.beginRefreshingCompletionBlock();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#pragma mark - 刷新动画时间控制
|
|
||||||
- (instancetype)setAnimationDisabled {
|
|
||||||
self.fastAnimationDuration = 0;
|
|
||||||
self.slowAnimationDuration = 0;
|
|
||||||
|
|
||||||
return self;
|
|
||||||
}
|
|
||||||
|
|
||||||
#pragma mark - <<< Deprecation compatible function >>> -
|
|
||||||
- (void)setEndRefreshingAnimateCompletionBlock:(MJRefreshComponentEndRefreshingCompletionBlock)endRefreshingAnimateCompletionBlock {
|
|
||||||
_endRefreshingAnimationBeginAction = endRefreshingAnimateCompletionBlock;
|
|
||||||
}
|
|
||||||
@end
|
|
||||||
|
|
||||||
@implementation UILabel(MJRefresh)
|
|
||||||
+ (instancetype)mj_label
|
|
||||||
{
|
|
||||||
UILabel *label = [[self alloc] init];
|
|
||||||
label.font = MJRefreshLabelFont;
|
|
||||||
label.textColor = MJRefreshLabelTextColor;
|
|
||||||
label.autoresizingMask = UIViewAutoresizingFlexibleWidth;
|
|
||||||
label.textAlignment = NSTextAlignmentCenter;
|
|
||||||
label.backgroundColor = [UIColor clearColor];
|
|
||||||
return label;
|
|
||||||
}
|
|
||||||
|
|
||||||
- (CGFloat)mj_textWidth {
|
|
||||||
CGFloat stringWidth = 0;
|
|
||||||
CGSize size = CGSizeMake(MAXFLOAT, MAXFLOAT);
|
|
||||||
|
|
||||||
if (self.attributedText) {
|
|
||||||
if (self.attributedText.length == 0) { return 0; }
|
|
||||||
stringWidth = [self.attributedText boundingRectWithSize:size
|
|
||||||
options:NSStringDrawingUsesLineFragmentOrigin
|
|
||||||
context:nil].size.width;
|
|
||||||
} else {
|
|
||||||
if (self.text.length == 0) { return 0; }
|
|
||||||
NSAssert(self.font != nil, @"请检查 mj_label's `font` 是否设置正确");
|
|
||||||
stringWidth = [self.text boundingRectWithSize:size
|
|
||||||
options:NSStringDrawingUsesLineFragmentOrigin
|
|
||||||
attributes:@{NSFontAttributeName:self.font}
|
|
||||||
context:nil].size.width;
|
|
||||||
}
|
|
||||||
return stringWidth;
|
|
||||||
}
|
|
||||||
@end
|
|
||||||
|
|
||||||
|
|
||||||
#pragma mark - <<< 为 Swift 扩展链式语法 >>> -
|
|
||||||
@implementation MJRefreshComponent (ChainingGrammar)
|
|
||||||
|
|
||||||
- (instancetype)autoChangeTransparency:(BOOL)isAutoChange {
|
|
||||||
self.automaticallyChangeAlpha = isAutoChange;
|
|
||||||
return self;
|
|
||||||
}
|
|
||||||
- (instancetype)afterBeginningAction:(MJRefreshComponentAction)action {
|
|
||||||
self.beginRefreshingCompletionBlock = action;
|
|
||||||
return self;
|
|
||||||
}
|
|
||||||
- (instancetype)endingAnimationBeginningAction:(MJRefreshComponentAction)action {
|
|
||||||
self.endRefreshingAnimationBeginAction = action;
|
|
||||||
return self;
|
|
||||||
}
|
|
||||||
- (instancetype)afterEndingAction:(MJRefreshComponentAction)action {
|
|
||||||
self.endRefreshingCompletionBlock = action;
|
|
||||||
return self;
|
|
||||||
}
|
|
||||||
|
|
||||||
- (instancetype)linkTo:(UIScrollView *)scrollView {
|
|
||||||
return self;
|
|
||||||
}
|
|
||||||
|
|
||||||
@end
|
|
||||||
37
Pods/MJRefresh/MJRefresh/Base/MJRefreshFooter.h
generated
37
Pods/MJRefresh/MJRefresh/Base/MJRefreshFooter.h
generated
@ -1,37 +0,0 @@
|
|||||||
// 代码地址: https://github.com/CoderMJLee/MJRefresh
|
|
||||||
// MJRefreshFooter.h
|
|
||||||
// MJRefresh
|
|
||||||
//
|
|
||||||
// Created by MJ Lee on 15/3/5.
|
|
||||||
// Copyright (c) 2015年 小码哥. All rights reserved.
|
|
||||||
// 上拉刷新控件
|
|
||||||
|
|
||||||
#if __has_include(<MJRefresh/MJRefreshComponent.h>)
|
|
||||||
#import <MJRefresh/MJRefreshComponent.h>
|
|
||||||
#else
|
|
||||||
#import "MJRefreshComponent.h"
|
|
||||||
#endif
|
|
||||||
|
|
||||||
NS_ASSUME_NONNULL_BEGIN
|
|
||||||
|
|
||||||
@interface MJRefreshFooter : MJRefreshComponent
|
|
||||||
/** 创建footer */
|
|
||||||
+ (instancetype)footerWithRefreshingBlock:(MJRefreshComponentAction)refreshingBlock;
|
|
||||||
/** 创建footer */
|
|
||||||
+ (instancetype)footerWithRefreshingTarget:(id)target refreshingAction:(SEL)action;
|
|
||||||
|
|
||||||
/** 提示没有更多的数据 */
|
|
||||||
- (void)endRefreshingWithNoMoreData;
|
|
||||||
- (void)noticeNoMoreData MJRefreshDeprecated("使用endRefreshingWithNoMoreData");
|
|
||||||
|
|
||||||
/** 重置没有更多的数据(消除没有更多数据的状态) */
|
|
||||||
- (void)resetNoMoreData;
|
|
||||||
|
|
||||||
/** 忽略多少scrollView的contentInset的bottom */
|
|
||||||
@property (assign, nonatomic) CGFloat ignoredScrollViewContentInsetBottom;
|
|
||||||
|
|
||||||
/** 自动根据有无数据来显示和隐藏(有数据就显示,没有数据隐藏。默认是NO) */
|
|
||||||
@property (assign, nonatomic, getter=isAutomaticallyHidden) BOOL automaticallyHidden MJRefreshDeprecated("已废弃此属性,开发者请自行控制footer的显示和隐藏");
|
|
||||||
@end
|
|
||||||
|
|
||||||
NS_ASSUME_NONNULL_END
|
|
||||||
71
Pods/MJRefresh/MJRefresh/Base/MJRefreshFooter.m
generated
71
Pods/MJRefresh/MJRefresh/Base/MJRefreshFooter.m
generated
@ -1,71 +0,0 @@
|
|||||||
// 代码地址: https://github.com/CoderMJLee/MJRefresh
|
|
||||||
// MJRefreshFooter.m
|
|
||||||
// MJRefresh
|
|
||||||
//
|
|
||||||
// Created by MJ Lee on 15/3/5.
|
|
||||||
// Copyright (c) 2015年 小码哥. All rights reserved.
|
|
||||||
//
|
|
||||||
|
|
||||||
#import "MJRefreshFooter.h"
|
|
||||||
#import "UIScrollView+MJRefresh.h"
|
|
||||||
#import "UIView+MJExtension.h"
|
|
||||||
|
|
||||||
@interface MJRefreshFooter()
|
|
||||||
|
|
||||||
@end
|
|
||||||
|
|
||||||
@implementation MJRefreshFooter
|
|
||||||
#pragma mark - 构造方法
|
|
||||||
+ (instancetype)footerWithRefreshingBlock:(MJRefreshComponentAction)refreshingBlock
|
|
||||||
{
|
|
||||||
MJRefreshFooter *cmp = [[self alloc] init];
|
|
||||||
cmp.refreshingBlock = refreshingBlock;
|
|
||||||
return cmp;
|
|
||||||
}
|
|
||||||
+ (instancetype)footerWithRefreshingTarget:(id)target refreshingAction:(SEL)action
|
|
||||||
{
|
|
||||||
MJRefreshFooter *cmp = [[self alloc] init];
|
|
||||||
[cmp setRefreshingTarget:target refreshingAction:action];
|
|
||||||
return cmp;
|
|
||||||
}
|
|
||||||
|
|
||||||
#pragma mark - 重写父类的方法
|
|
||||||
- (void)prepare
|
|
||||||
{
|
|
||||||
[super prepare];
|
|
||||||
|
|
||||||
// 设置自己的高度
|
|
||||||
self.mj_h = MJRefreshFooterHeight;
|
|
||||||
|
|
||||||
// 默认不会自动隐藏
|
|
||||||
// self.automaticallyHidden = NO;
|
|
||||||
}
|
|
||||||
|
|
||||||
#pragma mark . 链式语法部分 .
|
|
||||||
|
|
||||||
- (instancetype)linkTo:(UIScrollView *)scrollView {
|
|
||||||
scrollView.mj_footer = self;
|
|
||||||
return self;
|
|
||||||
}
|
|
||||||
|
|
||||||
#pragma mark - 公共方法
|
|
||||||
- (void)endRefreshingWithNoMoreData
|
|
||||||
{
|
|
||||||
MJRefreshDispatchAsyncOnMainQueue(self.state = MJRefreshStateNoMoreData;)
|
|
||||||
}
|
|
||||||
|
|
||||||
- (void)noticeNoMoreData
|
|
||||||
{
|
|
||||||
[self endRefreshingWithNoMoreData];
|
|
||||||
}
|
|
||||||
|
|
||||||
- (void)resetNoMoreData
|
|
||||||
{
|
|
||||||
MJRefreshDispatchAsyncOnMainQueue(self.state = MJRefreshStateIdle;)
|
|
||||||
}
|
|
||||||
|
|
||||||
- (void)setAutomaticallyHidden:(BOOL)automaticallyHidden
|
|
||||||
{
|
|
||||||
_automaticallyHidden = automaticallyHidden;
|
|
||||||
}
|
|
||||||
@end
|
|
||||||
35
Pods/MJRefresh/MJRefresh/Base/MJRefreshHeader.h
generated
35
Pods/MJRefresh/MJRefresh/Base/MJRefreshHeader.h
generated
@ -1,35 +0,0 @@
|
|||||||
// 代码地址: https://github.com/CoderMJLee/MJRefresh
|
|
||||||
// MJRefreshHeader.h
|
|
||||||
// MJRefresh
|
|
||||||
//
|
|
||||||
// Created by MJ Lee on 15/3/4.
|
|
||||||
// Copyright (c) 2015年 小码哥. All rights reserved.
|
|
||||||
// 下拉刷新控件:负责监控用户下拉的状态
|
|
||||||
|
|
||||||
#if __has_include(<MJRefresh/MJRefreshComponent.h>)
|
|
||||||
#import <MJRefresh/MJRefreshComponent.h>
|
|
||||||
#else
|
|
||||||
#import "MJRefreshComponent.h"
|
|
||||||
#endif
|
|
||||||
|
|
||||||
NS_ASSUME_NONNULL_BEGIN
|
|
||||||
|
|
||||||
@interface MJRefreshHeader : MJRefreshComponent
|
|
||||||
/** 创建header */
|
|
||||||
+ (instancetype)headerWithRefreshingBlock:(MJRefreshComponentAction)refreshingBlock;
|
|
||||||
/** 创建header */
|
|
||||||
+ (instancetype)headerWithRefreshingTarget:(id)target refreshingAction:(SEL)action;
|
|
||||||
|
|
||||||
/** 这个key用来存储上一次下拉刷新成功的时间 */
|
|
||||||
@property (copy, nonatomic) NSString *lastUpdatedTimeKey;
|
|
||||||
/** 上一次下拉刷新成功的时间 */
|
|
||||||
@property (strong, nonatomic, readonly, nullable) NSDate *lastUpdatedTime;
|
|
||||||
|
|
||||||
/** 忽略多少scrollView的contentInset的top */
|
|
||||||
@property (assign, nonatomic) CGFloat ignoredScrollViewContentInsetTop;
|
|
||||||
|
|
||||||
/** 默认是关闭状态, 如果遇到 CollectionView 的动画异常问题可以尝试打开 */
|
|
||||||
@property (nonatomic) BOOL isCollectionViewAnimationBug;
|
|
||||||
@end
|
|
||||||
|
|
||||||
NS_ASSUME_NONNULL_END
|
|
||||||
297
Pods/MJRefresh/MJRefresh/Base/MJRefreshHeader.m
generated
297
Pods/MJRefresh/MJRefresh/Base/MJRefreshHeader.m
generated
@ -1,297 +0,0 @@
|
|||||||
// 代码地址: https://github.com/CoderMJLee/MJRefresh
|
|
||||||
// MJRefreshHeader.m
|
|
||||||
// MJRefresh
|
|
||||||
//
|
|
||||||
// Created by MJ Lee on 15/3/4.
|
|
||||||
// Copyright (c) 2015年 小码哥. All rights reserved.
|
|
||||||
//
|
|
||||||
|
|
||||||
#import "MJRefreshHeader.h"
|
|
||||||
#import "UIView+MJExtension.h"
|
|
||||||
#import "UIScrollView+MJExtension.h"
|
|
||||||
#import "UIScrollView+MJRefresh.h"
|
|
||||||
|
|
||||||
NSString * const MJRefreshHeaderRefreshing2IdleBoundsKey = @"MJRefreshHeaderRefreshing2IdleBounds";
|
|
||||||
NSString * const MJRefreshHeaderRefreshingBoundsKey = @"MJRefreshHeaderRefreshingBounds";
|
|
||||||
|
|
||||||
@interface MJRefreshHeader() <CAAnimationDelegate>
|
|
||||||
@property (assign, nonatomic) CGFloat insetTDelta;
|
|
||||||
@end
|
|
||||||
|
|
||||||
@implementation MJRefreshHeader
|
|
||||||
#pragma mark - 构造方法
|
|
||||||
+ (instancetype)headerWithRefreshingBlock:(MJRefreshComponentAction)refreshingBlock
|
|
||||||
{
|
|
||||||
MJRefreshHeader *cmp = [[self alloc] init];
|
|
||||||
cmp.refreshingBlock = refreshingBlock;
|
|
||||||
return cmp;
|
|
||||||
}
|
|
||||||
+ (instancetype)headerWithRefreshingTarget:(id)target refreshingAction:(SEL)action
|
|
||||||
{
|
|
||||||
MJRefreshHeader *cmp = [[self alloc] init];
|
|
||||||
[cmp setRefreshingTarget:target refreshingAction:action];
|
|
||||||
return cmp;
|
|
||||||
}
|
|
||||||
|
|
||||||
#pragma mark - 覆盖父类的方法
|
|
||||||
- (void)prepare
|
|
||||||
{
|
|
||||||
[super prepare];
|
|
||||||
|
|
||||||
// 设置key
|
|
||||||
self.lastUpdatedTimeKey = MJRefreshHeaderLastUpdatedTimeKey;
|
|
||||||
|
|
||||||
// 设置高度
|
|
||||||
self.mj_h = MJRefreshHeaderHeight;
|
|
||||||
}
|
|
||||||
|
|
||||||
- (void)placeSubviews
|
|
||||||
{
|
|
||||||
[super placeSubviews];
|
|
||||||
|
|
||||||
// 设置y值(当自己的高度发生改变了,肯定要重新调整Y值,所以放到placeSubviews方法中设置y值)
|
|
||||||
self.mj_y = - self.mj_h - self.ignoredScrollViewContentInsetTop;
|
|
||||||
}
|
|
||||||
|
|
||||||
- (void)resetInset {
|
|
||||||
if (@available(iOS 11.0, *)) {
|
|
||||||
} else {
|
|
||||||
// 如果 iOS 10 及以下系统在刷新时, push 新的 VC, 等待刷新完成后回来, 会导致顶部 Insets.top 异常, 不能 resetInset, 检查一下这种特殊情况
|
|
||||||
if (!self.window) { return; }
|
|
||||||
}
|
|
||||||
|
|
||||||
// sectionheader停留解决
|
|
||||||
CGFloat insetT = - self.scrollView.mj_offsetY > _scrollViewOriginalInset.top ? - self.scrollView.mj_offsetY : _scrollViewOriginalInset.top;
|
|
||||||
insetT = insetT > self.mj_h + _scrollViewOriginalInset.top ? self.mj_h + _scrollViewOriginalInset.top : insetT;
|
|
||||||
self.insetTDelta = _scrollViewOriginalInset.top - insetT;
|
|
||||||
// 避免 CollectionView 在使用根据 Autolayout 和 内容自动伸缩 Cell, 刷新时导致的 Layout 异常渲染问题
|
|
||||||
if (fabs(self.scrollView.mj_insetT - insetT) > FLT_EPSILON) {
|
|
||||||
self.scrollView.mj_insetT = insetT;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
- (void)scrollViewContentOffsetDidChange:(NSDictionary *)change
|
|
||||||
{
|
|
||||||
[super scrollViewContentOffsetDidChange:change];
|
|
||||||
|
|
||||||
// 在刷新的refreshing状态
|
|
||||||
if (self.state == MJRefreshStateRefreshing) {
|
|
||||||
[self resetInset];
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// 跳转到下一个控制器时,contentInset可能会变
|
|
||||||
_scrollViewOriginalInset = self.scrollView.mj_inset;
|
|
||||||
|
|
||||||
// 当前的contentOffset
|
|
||||||
CGFloat offsetY = self.scrollView.mj_offsetY;
|
|
||||||
// 头部控件刚好出现的offsetY
|
|
||||||
CGFloat happenOffsetY = - self.scrollViewOriginalInset.top;
|
|
||||||
|
|
||||||
// 如果是向上滚动到看不见头部控件,直接返回
|
|
||||||
// >= -> >
|
|
||||||
if (offsetY > happenOffsetY) return;
|
|
||||||
|
|
||||||
// 普通 和 即将刷新 的临界点
|
|
||||||
CGFloat normal2pullingOffsetY = happenOffsetY - self.mj_h;
|
|
||||||
CGFloat pullingPercent = (happenOffsetY - offsetY) / self.mj_h;
|
|
||||||
|
|
||||||
if (self.scrollView.isDragging) { // 如果正在拖拽
|
|
||||||
self.pullingPercent = pullingPercent;
|
|
||||||
if (self.state == MJRefreshStateIdle && offsetY < normal2pullingOffsetY) {
|
|
||||||
// 转为即将刷新状态
|
|
||||||
self.state = MJRefreshStatePulling;
|
|
||||||
} else if (self.state == MJRefreshStatePulling && offsetY >= normal2pullingOffsetY) {
|
|
||||||
// 转为普通状态
|
|
||||||
self.state = MJRefreshStateIdle;
|
|
||||||
}
|
|
||||||
} else if (self.state == MJRefreshStatePulling) {// 即将刷新 && 手松开
|
|
||||||
// 开始刷新
|
|
||||||
[self beginRefreshing];
|
|
||||||
} else if (pullingPercent < 1) {
|
|
||||||
self.pullingPercent = pullingPercent;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
- (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:self.slowAnimationDuration 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的动画
|
|
||||||
fix issue#225 https://github.com/CoderMJLee/MJRefresh/issues/225
|
|
||||||
另一种解法 pull#737 https://github.com/CoderMJLee/MJRefresh/pull/737
|
|
||||||
|
|
||||||
同时, 处理了 Refreshing 中的动画替换.
|
|
||||||
*/
|
|
||||||
|
|
||||||
// 由于修改 Inset 会导致 self.pullingPercent 联动设置 self.alpha, 故提前获取 alpha 值, 后续用于还原 alpha 动画
|
|
||||||
CGFloat viewAlpha = self.alpha;
|
|
||||||
|
|
||||||
self.scrollView.mj_insetT += self.insetTDelta;
|
|
||||||
// 禁用交互, 如果不禁用可能会引起渲染问题.
|
|
||||||
self.scrollView.userInteractionEnabled = NO;
|
|
||||||
|
|
||||||
//CAAnimation keyPath 不支持 contentInset 用Bounds的动画代替
|
|
||||||
CABasicAnimation *boundsAnimation = [CABasicAnimation animationWithKeyPath:@"bounds"];
|
|
||||||
boundsAnimation.fromValue = [NSValue valueWithCGRect:CGRectOffset(self.scrollView.bounds, 0, self.insetTDelta)];
|
|
||||||
boundsAnimation.duration = self.slowAnimationDuration;
|
|
||||||
//在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 = self.slowAnimationDuration;
|
|
||||||
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) {
|
|
||||||
[UIView animateWithDuration:self.fastAnimationDuration 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不支持 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 = self.fastAnimationDuration;
|
|
||||||
//在delegate里移除
|
|
||||||
boundsAnimation.removedOnCompletion = NO;
|
|
||||||
boundsAnimation.fillMode = kCAFillModeBoth;
|
|
||||||
boundsAnimation.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut];
|
|
||||||
boundsAnimation.delegate = self;
|
|
||||||
[boundsAnimation setValue:MJRefreshHeaderRefreshingBoundsKey forKey:@"identity"];
|
|
||||||
[self.scrollView.layer addAnimation:boundsAnimation forKey:MJRefreshHeaderRefreshingBoundsKey];
|
|
||||||
} else {
|
|
||||||
[self executeRefreshingCallback];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#pragma mark . 链式语法部分 .
|
|
||||||
|
|
||||||
- (instancetype)linkTo:(UIScrollView *)scrollView {
|
|
||||||
scrollView.mj_header = self;
|
|
||||||
return self;
|
|
||||||
}
|
|
||||||
|
|
||||||
#pragma mark - CAAnimationDelegate
|
|
||||||
- (void)animationDidStop:(CAAnimation *)anim finished:(BOOL)flag {
|
|
||||||
NSString *identity = [anim valueForKey:@"identity"];
|
|
||||||
if ([identity isEqualToString:MJRefreshHeaderRefreshing2IdleBoundsKey]) {
|
|
||||||
self.pullingPercent = 0.0;
|
|
||||||
self.scrollView.userInteractionEnabled = YES;
|
|
||||||
if (self.endRefreshingCompletionBlock) {
|
|
||||||
self.endRefreshingCompletionBlock();
|
|
||||||
}
|
|
||||||
} else if ([identity isEqualToString:MJRefreshHeaderRefreshingBoundsKey]) {
|
|
||||||
// 避免出现 end 先于 Refreshing 状态
|
|
||||||
if (self.state != MJRefreshStateIdle) {
|
|
||||||
CGFloat top = self.scrollViewOriginalInset.top + self.mj_h;
|
|
||||||
self.scrollView.mj_insetT = top;
|
|
||||||
// 设置最终滚动位置
|
|
||||||
CGPoint offset = self.scrollView.contentOffset;
|
|
||||||
offset.y = -top;
|
|
||||||
[self.scrollView setContentOffset:offset animated:NO];
|
|
||||||
}
|
|
||||||
self.scrollView.userInteractionEnabled = YES;
|
|
||||||
[self executeRefreshingCallback];
|
|
||||||
}
|
|
||||||
|
|
||||||
if ([self.scrollView.layer animationForKey:MJRefreshHeaderRefreshing2IdleBoundsKey]) {
|
|
||||||
[self.scrollView.layer removeAnimationForKey:MJRefreshHeaderRefreshing2IdleBoundsKey];
|
|
||||||
}
|
|
||||||
|
|
||||||
if ([self.scrollView.layer animationForKey:MJRefreshHeaderRefreshingBoundsKey]) {
|
|
||||||
[self.scrollView.layer removeAnimationForKey:MJRefreshHeaderRefreshingBoundsKey];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#pragma mark - 公共方法
|
|
||||||
- (NSDate *)lastUpdatedTime
|
|
||||||
{
|
|
||||||
return [[NSUserDefaults standardUserDefaults] objectForKey:self.lastUpdatedTimeKey];
|
|
||||||
}
|
|
||||||
|
|
||||||
- (void)setIgnoredScrollViewContentInsetTop:(CGFloat)ignoredScrollViewContentInsetTop {
|
|
||||||
_ignoredScrollViewContentInsetTop = ignoredScrollViewContentInsetTop;
|
|
||||||
|
|
||||||
self.mj_y = - self.mj_h - _ignoredScrollViewContentInsetTop;
|
|
||||||
}
|
|
||||||
|
|
||||||
@end
|
|
||||||
30
Pods/MJRefresh/MJRefresh/Base/MJRefreshTrailer.h
generated
30
Pods/MJRefresh/MJRefresh/Base/MJRefreshTrailer.h
generated
@ -1,30 +0,0 @@
|
|||||||
//
|
|
||||||
// MJRefreshTrailer.h
|
|
||||||
// MJRefresh
|
|
||||||
//
|
|
||||||
// Created by kinarobin on 2020/5/3.
|
|
||||||
// Copyright © 2020 小码哥. All rights reserved.
|
|
||||||
//
|
|
||||||
|
|
||||||
#if __has_include(<MJRefresh/MJRefreshComponent.h>)
|
|
||||||
#import <MJRefresh/MJRefreshComponent.h>
|
|
||||||
#else
|
|
||||||
#import "MJRefreshComponent.h"
|
|
||||||
#endif
|
|
||||||
|
|
||||||
NS_ASSUME_NONNULL_BEGIN
|
|
||||||
|
|
||||||
@interface MJRefreshTrailer : MJRefreshComponent
|
|
||||||
|
|
||||||
/** 创建trailer*/
|
|
||||||
+ (instancetype)trailerWithRefreshingBlock:(MJRefreshComponentAction)refreshingBlock;
|
|
||||||
/** 创建trailer */
|
|
||||||
+ (instancetype)trailerWithRefreshingTarget:(id)target refreshingAction:(SEL)action;
|
|
||||||
|
|
||||||
/** 忽略多少scrollView的contentInset的right */
|
|
||||||
@property (assign, nonatomic) CGFloat ignoredScrollViewContentInsetRight;
|
|
||||||
|
|
||||||
|
|
||||||
@end
|
|
||||||
|
|
||||||
NS_ASSUME_NONNULL_END
|
|
||||||
179
Pods/MJRefresh/MJRefresh/Base/MJRefreshTrailer.m
generated
179
Pods/MJRefresh/MJRefresh/Base/MJRefreshTrailer.m
generated
@ -1,179 +0,0 @@
|
|||||||
//
|
|
||||||
// MJRefreshTrailer.m
|
|
||||||
// MJRefresh
|
|
||||||
//
|
|
||||||
// Created by kinarobin on 2020/5/3.
|
|
||||||
// Copyright © 2020 小码哥. All rights reserved.
|
|
||||||
//
|
|
||||||
|
|
||||||
#import "MJRefreshTrailer.h"
|
|
||||||
#import "UIView+MJExtension.h"
|
|
||||||
#import "UIScrollView+MJRefresh.h"
|
|
||||||
#import "UIScrollView+MJExtension.h"
|
|
||||||
|
|
||||||
@interface MJRefreshTrailer()
|
|
||||||
@property (assign, nonatomic) NSInteger lastRefreshCount;
|
|
||||||
@property (assign, nonatomic) CGFloat lastRightDelta;
|
|
||||||
@end
|
|
||||||
|
|
||||||
@implementation MJRefreshTrailer
|
|
||||||
|
|
||||||
#pragma mark - 构造方法
|
|
||||||
+ (instancetype)trailerWithRefreshingBlock:(MJRefreshComponentAction)refreshingBlock {
|
|
||||||
MJRefreshTrailer *cmp = [[self alloc] init];
|
|
||||||
cmp.refreshingBlock = refreshingBlock;
|
|
||||||
return cmp;
|
|
||||||
}
|
|
||||||
|
|
||||||
+ (instancetype)trailerWithRefreshingTarget:(id)target refreshingAction:(SEL)action {
|
|
||||||
MJRefreshTrailer *cmp = [[self alloc] init];
|
|
||||||
[cmp setRefreshingTarget:target refreshingAction:action];
|
|
||||||
return cmp;
|
|
||||||
}
|
|
||||||
|
|
||||||
- (void)scrollViewContentOffsetDidChange:(NSDictionary *)change {
|
|
||||||
[super scrollViewContentOffsetDidChange:change];
|
|
||||||
|
|
||||||
// 如果正在刷新,直接返回
|
|
||||||
if (self.state == MJRefreshStateRefreshing) return;
|
|
||||||
|
|
||||||
_scrollViewOriginalInset = self.scrollView.mj_inset;
|
|
||||||
|
|
||||||
// 当前的contentOffset
|
|
||||||
CGFloat currentOffsetX = self.scrollView.mj_offsetX;
|
|
||||||
// 尾部控件刚好出现的offsetX
|
|
||||||
CGFloat happenOffsetX = [self happenOffsetX];
|
|
||||||
// 如果是向右滚动到看不见右边控件,直接返回
|
|
||||||
if (currentOffsetX <= happenOffsetX) return;
|
|
||||||
|
|
||||||
CGFloat pullingPercent = (currentOffsetX - happenOffsetX) / self.mj_w;
|
|
||||||
|
|
||||||
// 如果已全部加载,仅设置pullingPercent,然后返回
|
|
||||||
if (self.state == MJRefreshStateNoMoreData) {
|
|
||||||
self.pullingPercent = pullingPercent;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (self.scrollView.isDragging) {
|
|
||||||
self.pullingPercent = pullingPercent;
|
|
||||||
// 普通 和 即将刷新 的临界点
|
|
||||||
CGFloat normal2pullingOffsetX = happenOffsetX + self.mj_w;
|
|
||||||
|
|
||||||
if (self.state == MJRefreshStateIdle && currentOffsetX > normal2pullingOffsetX) {
|
|
||||||
self.state = MJRefreshStatePulling;
|
|
||||||
} else if (self.state == MJRefreshStatePulling && currentOffsetX <= normal2pullingOffsetX) {
|
|
||||||
// 转为普通状态
|
|
||||||
self.state = MJRefreshStateIdle;
|
|
||||||
}
|
|
||||||
} else if (self.state == MJRefreshStatePulling) {// 即将刷新 && 手松开
|
|
||||||
// 开始刷新
|
|
||||||
[self beginRefreshing];
|
|
||||||
} else if (pullingPercent < 1) {
|
|
||||||
self.pullingPercent = pullingPercent;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
- (void)setState:(MJRefreshState)state {
|
|
||||||
MJRefreshCheckState
|
|
||||||
// 根据状态来设置属性
|
|
||||||
if (state == MJRefreshStateNoMoreData || state == MJRefreshStateIdle) {
|
|
||||||
// 刷新完毕
|
|
||||||
if (MJRefreshStateRefreshing == oldState) {
|
|
||||||
[UIView animateWithDuration:self.slowAnimationDuration animations:^{
|
|
||||||
if (self.endRefreshingAnimationBeginAction) {
|
|
||||||
self.endRefreshingAnimationBeginAction();
|
|
||||||
}
|
|
||||||
|
|
||||||
self.scrollView.mj_insetR -= self.lastRightDelta;
|
|
||||||
// 自动调整透明度
|
|
||||||
if (self.isAutomaticallyChangeAlpha) self.alpha = 0.0;
|
|
||||||
} completion:^(BOOL finished) {
|
|
||||||
self.pullingPercent = 0.0;
|
|
||||||
|
|
||||||
if (self.endRefreshingCompletionBlock) {
|
|
||||||
self.endRefreshingCompletionBlock();
|
|
||||||
}
|
|
||||||
}];
|
|
||||||
}
|
|
||||||
|
|
||||||
CGFloat deltaW = [self widthForContentBreakView];
|
|
||||||
// 刚刷新完毕
|
|
||||||
if (MJRefreshStateRefreshing == oldState && deltaW > 0 && self.scrollView.mj_totalDataCount != self.lastRefreshCount) {
|
|
||||||
self.scrollView.mj_offsetX = self.scrollView.mj_offsetX;
|
|
||||||
}
|
|
||||||
} else if (state == MJRefreshStateRefreshing) {
|
|
||||||
// 记录刷新前的数量
|
|
||||||
self.lastRefreshCount = self.scrollView.mj_totalDataCount;
|
|
||||||
|
|
||||||
[UIView animateWithDuration:self.fastAnimationDuration animations:^{
|
|
||||||
CGFloat right = self.mj_w + self.scrollViewOriginalInset.right;
|
|
||||||
CGFloat deltaW = [self widthForContentBreakView];
|
|
||||||
if (deltaW < 0) { // 如果内容宽度小于view的宽度
|
|
||||||
right -= deltaW;
|
|
||||||
}
|
|
||||||
self.lastRightDelta = right - self.scrollView.mj_insetR;
|
|
||||||
self.scrollView.mj_insetR = right;
|
|
||||||
|
|
||||||
// 设置滚动位置
|
|
||||||
CGPoint offset = self.scrollView.contentOffset;
|
|
||||||
offset.x = [self happenOffsetX] + self.mj_w;
|
|
||||||
[self.scrollView setContentOffset:offset animated:NO];
|
|
||||||
} completion:^(BOOL finished) {
|
|
||||||
[self executeRefreshingCallback];
|
|
||||||
}];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
- (void)scrollViewContentSizeDidChange:(NSDictionary *)change {
|
|
||||||
[super scrollViewContentSizeDidChange:change];
|
|
||||||
|
|
||||||
// 内容的宽度
|
|
||||||
CGFloat contentWidth = self.scrollView.mj_contentW + self.ignoredScrollViewContentInsetRight;
|
|
||||||
// 表格的宽度
|
|
||||||
CGFloat scrollWidth = self.scrollView.mj_w - self.scrollViewOriginalInset.left - self.scrollViewOriginalInset.right + self.ignoredScrollViewContentInsetRight;
|
|
||||||
// 设置位置和尺寸
|
|
||||||
self.mj_x = MAX(contentWidth, scrollWidth);
|
|
||||||
}
|
|
||||||
|
|
||||||
- (void)placeSubviews {
|
|
||||||
[super placeSubviews];
|
|
||||||
|
|
||||||
self.mj_h = _scrollView.mj_h;
|
|
||||||
// 设置自己的宽度
|
|
||||||
self.mj_w = MJRefreshTrailWidth;
|
|
||||||
}
|
|
||||||
|
|
||||||
- (void)willMoveToSuperview:(UIView *)newSuperview {
|
|
||||||
[super willMoveToSuperview:newSuperview];
|
|
||||||
|
|
||||||
if (newSuperview) {
|
|
||||||
// 设置支持水平弹簧效果
|
|
||||||
_scrollView.alwaysBounceHorizontal = YES;
|
|
||||||
_scrollView.alwaysBounceVertical = NO;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#pragma mark . 链式语法部分 .
|
|
||||||
|
|
||||||
- (instancetype)linkTo:(UIScrollView *)scrollView {
|
|
||||||
scrollView.mj_trailer = self;
|
|
||||||
return self;
|
|
||||||
}
|
|
||||||
|
|
||||||
#pragma mark - 刚好看到上拉刷新控件时的contentOffset.x
|
|
||||||
- (CGFloat)happenOffsetX {
|
|
||||||
CGFloat deltaW = [self widthForContentBreakView];
|
|
||||||
if (deltaW > 0) {
|
|
||||||
return deltaW - self.scrollViewOriginalInset.left;
|
|
||||||
} else {
|
|
||||||
return - self.scrollViewOriginalInset.left;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#pragma mark 获得scrollView的内容 超出 view 的宽度
|
|
||||||
- (CGFloat)widthForContentBreakView {
|
|
||||||
CGFloat w = self.scrollView.frame.size.width - self.scrollViewOriginalInset.right - self.scrollViewOriginalInset.left;
|
|
||||||
return self.scrollView.contentSize.width - w;
|
|
||||||
}
|
|
||||||
|
|
||||||
@end
|
|
||||||
@ -1,25 +0,0 @@
|
|||||||
//
|
|
||||||
// MJRefreshAutoGifFooter.h
|
|
||||||
// MJRefresh
|
|
||||||
//
|
|
||||||
// Created by MJ Lee on 15/4/24.
|
|
||||||
// Copyright (c) 2015年 小码哥. All rights reserved.
|
|
||||||
//
|
|
||||||
|
|
||||||
#if __has_include(<MJRefresh/MJRefreshAutoStateFooter.h>)
|
|
||||||
#import <MJRefresh/MJRefreshAutoStateFooter.h>
|
|
||||||
#else
|
|
||||||
#import "MJRefreshAutoStateFooter.h"
|
|
||||||
#endif
|
|
||||||
|
|
||||||
NS_ASSUME_NONNULL_BEGIN
|
|
||||||
|
|
||||||
@interface MJRefreshAutoGifFooter : MJRefreshAutoStateFooter
|
|
||||||
@property (weak, nonatomic, readonly) UIImageView *gifView;
|
|
||||||
|
|
||||||
/** 设置state状态下的动画图片images 动画持续时间duration*/
|
|
||||||
- (instancetype)setImages:(NSArray *)images duration:(NSTimeInterval)duration forState:(MJRefreshState)state;
|
|
||||||
- (instancetype)setImages:(NSArray *)images forState:(MJRefreshState)state;
|
|
||||||
@end
|
|
||||||
|
|
||||||
NS_ASSUME_NONNULL_END
|
|
||||||
@ -1,121 +0,0 @@
|
|||||||
//
|
|
||||||
// MJRefreshAutoGifFooter.m
|
|
||||||
// MJRefresh
|
|
||||||
//
|
|
||||||
// Created by MJ Lee on 15/4/24.
|
|
||||||
// Copyright (c) 2015年 小码哥. All rights reserved.
|
|
||||||
//
|
|
||||||
|
|
||||||
#import "MJRefreshAutoGifFooter.h"
|
|
||||||
#import "NSBundle+MJRefresh.h"
|
|
||||||
#import "UIView+MJExtension.h"
|
|
||||||
#import "UIScrollView+MJExtension.h"
|
|
||||||
#import "UIScrollView+MJRefresh.h"
|
|
||||||
|
|
||||||
@interface MJRefreshAutoGifFooter()
|
|
||||||
{
|
|
||||||
__unsafe_unretained UIImageView *_gifView;
|
|
||||||
}
|
|
||||||
/** 所有状态对应的动画图片 */
|
|
||||||
@property (strong, nonatomic) NSMutableDictionary *stateImages;
|
|
||||||
/** 所有状态对应的动画时间 */
|
|
||||||
@property (strong, nonatomic) NSMutableDictionary *stateDurations;
|
|
||||||
@end
|
|
||||||
|
|
||||||
@implementation MJRefreshAutoGifFooter
|
|
||||||
#pragma mark - 懒加载
|
|
||||||
- (UIImageView *)gifView
|
|
||||||
{
|
|
||||||
if (!_gifView) {
|
|
||||||
UIImageView *gifView = [[UIImageView alloc] init];
|
|
||||||
[self addSubview:_gifView = gifView];
|
|
||||||
}
|
|
||||||
return _gifView;
|
|
||||||
}
|
|
||||||
|
|
||||||
- (NSMutableDictionary *)stateImages
|
|
||||||
{
|
|
||||||
if (!_stateImages) {
|
|
||||||
self.stateImages = [NSMutableDictionary dictionary];
|
|
||||||
}
|
|
||||||
return _stateImages;
|
|
||||||
}
|
|
||||||
|
|
||||||
- (NSMutableDictionary *)stateDurations
|
|
||||||
{
|
|
||||||
if (!_stateDurations) {
|
|
||||||
self.stateDurations = [NSMutableDictionary dictionary];
|
|
||||||
}
|
|
||||||
return _stateDurations;
|
|
||||||
}
|
|
||||||
|
|
||||||
#pragma mark - 公共方法
|
|
||||||
- (instancetype)setImages:(NSArray *)images duration:(NSTimeInterval)duration forState:(MJRefreshState)state
|
|
||||||
{
|
|
||||||
if (images == nil) return self;
|
|
||||||
|
|
||||||
self.stateImages[@(state)] = images;
|
|
||||||
self.stateDurations[@(state)] = @(duration);
|
|
||||||
|
|
||||||
/* 根据图片设置控件的高度 */
|
|
||||||
UIImage *image = [images firstObject];
|
|
||||||
if (image.size.height > self.mj_h) {
|
|
||||||
self.mj_h = image.size.height;
|
|
||||||
}
|
|
||||||
return self;
|
|
||||||
}
|
|
||||||
|
|
||||||
- (instancetype)setImages:(NSArray *)images forState:(MJRefreshState)state
|
|
||||||
{
|
|
||||||
return [self setImages:images duration:images.count * 0.1 forState:state];
|
|
||||||
}
|
|
||||||
|
|
||||||
#pragma mark - 实现父类的方法
|
|
||||||
- (void)prepare
|
|
||||||
{
|
|
||||||
[super prepare];
|
|
||||||
|
|
||||||
// 初始化间距
|
|
||||||
self.labelLeftInset = 20;
|
|
||||||
}
|
|
||||||
|
|
||||||
- (void)placeSubviews
|
|
||||||
{
|
|
||||||
[super placeSubviews];
|
|
||||||
|
|
||||||
if (self.gifView.constraints.count) return;
|
|
||||||
|
|
||||||
self.gifView.frame = self.bounds;
|
|
||||||
if (self.isRefreshingTitleHidden) {
|
|
||||||
self.gifView.contentMode = UIViewContentModeCenter;
|
|
||||||
} else {
|
|
||||||
self.gifView.contentMode = UIViewContentModeRight;
|
|
||||||
self.gifView.mj_w = self.mj_w * 0.5 - self.labelLeftInset - self.stateLabel.mj_textWidth * 0.5;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
- (void)setState:(MJRefreshState)state
|
|
||||||
{
|
|
||||||
MJRefreshCheckState
|
|
||||||
|
|
||||||
// 根据状态做事情
|
|
||||||
if (state == MJRefreshStateRefreshing) {
|
|
||||||
NSArray *images = self.stateImages[@(state)];
|
|
||||||
if (images.count == 0) return;
|
|
||||||
[self.gifView stopAnimating];
|
|
||||||
|
|
||||||
self.gifView.hidden = NO;
|
|
||||||
if (images.count == 1) { // 单张图片
|
|
||||||
self.gifView.image = [images lastObject];
|
|
||||||
} else { // 多张图片
|
|
||||||
self.gifView.animationImages = images;
|
|
||||||
self.gifView.animationDuration = [self.stateDurations[@(state)] doubleValue];
|
|
||||||
[self.gifView startAnimating];
|
|
||||||
}
|
|
||||||
} else if (state == MJRefreshStateNoMoreData || state == MJRefreshStateIdle) {
|
|
||||||
[self.gifView stopAnimating];
|
|
||||||
self.gifView.hidden = YES;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@end
|
|
||||||
|
|
||||||
@ -1,25 +0,0 @@
|
|||||||
//
|
|
||||||
// MJRefreshAutoNormalFooter.h
|
|
||||||
// MJRefresh
|
|
||||||
//
|
|
||||||
// Created by MJ Lee on 15/4/24.
|
|
||||||
// Copyright (c) 2015年 小码哥. All rights reserved.
|
|
||||||
//
|
|
||||||
|
|
||||||
#if __has_include(<MJRefresh/MJRefreshAutoStateFooter.h>)
|
|
||||||
#import <MJRefresh/MJRefreshAutoStateFooter.h>
|
|
||||||
#else
|
|
||||||
#import "MJRefreshAutoStateFooter.h"
|
|
||||||
#endif
|
|
||||||
|
|
||||||
NS_ASSUME_NONNULL_BEGIN
|
|
||||||
|
|
||||||
@interface MJRefreshAutoNormalFooter : MJRefreshAutoStateFooter
|
|
||||||
@property (weak, nonatomic, readonly) UIActivityIndicatorView *loadingView;
|
|
||||||
|
|
||||||
/** 菊花的样式 */
|
|
||||||
@property (assign, nonatomic) UIActivityIndicatorViewStyle activityIndicatorViewStyle MJRefreshDeprecated("first deprecated in 3.2.2 - Use `loadingView` property");
|
|
||||||
@end
|
|
||||||
|
|
||||||
|
|
||||||
NS_ASSUME_NONNULL_END
|
|
||||||
@ -1,81 +0,0 @@
|
|||||||
//
|
|
||||||
// MJRefreshAutoNormalFooter.m
|
|
||||||
// MJRefresh
|
|
||||||
//
|
|
||||||
// Created by MJ Lee on 15/4/24.
|
|
||||||
// Copyright (c) 2015年 小码哥. All rights reserved.
|
|
||||||
//
|
|
||||||
|
|
||||||
#import "MJRefreshAutoNormalFooter.h"
|
|
||||||
#import "NSBundle+MJRefresh.h"
|
|
||||||
#import "UIView+MJExtension.h"
|
|
||||||
#import "UIScrollView+MJExtension.h"
|
|
||||||
#import "UIScrollView+MJRefresh.h"
|
|
||||||
|
|
||||||
@interface MJRefreshAutoNormalFooter()
|
|
||||||
@property (weak, nonatomic) UIActivityIndicatorView *loadingView;
|
|
||||||
@end
|
|
||||||
|
|
||||||
@implementation MJRefreshAutoNormalFooter
|
|
||||||
#pragma mark - 懒加载子控件
|
|
||||||
- (UIActivityIndicatorView *)loadingView
|
|
||||||
{
|
|
||||||
if (!_loadingView) {
|
|
||||||
UIActivityIndicatorView *loadingView = [[UIActivityIndicatorView alloc] initWithActivityIndicatorStyle:_activityIndicatorViewStyle];
|
|
||||||
loadingView.hidesWhenStopped = YES;
|
|
||||||
[self addSubview:_loadingView = loadingView];
|
|
||||||
}
|
|
||||||
return _loadingView;
|
|
||||||
}
|
|
||||||
|
|
||||||
- (void)setActivityIndicatorViewStyle:(UIActivityIndicatorViewStyle)activityIndicatorViewStyle
|
|
||||||
{
|
|
||||||
_activityIndicatorViewStyle = activityIndicatorViewStyle;
|
|
||||||
|
|
||||||
[self.loadingView removeFromSuperview];
|
|
||||||
self.loadingView = nil;
|
|
||||||
[self setNeedsLayout];
|
|
||||||
}
|
|
||||||
#pragma mark - 重写父类的方法
|
|
||||||
- (void)prepare
|
|
||||||
{
|
|
||||||
[super prepare];
|
|
||||||
|
|
||||||
#if __IPHONE_OS_VERSION_MAX_ALLOWED >= 130000
|
|
||||||
if (@available(iOS 13.0, *)) {
|
|
||||||
_activityIndicatorViewStyle = UIActivityIndicatorViewStyleMedium;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
_activityIndicatorViewStyle = UIActivityIndicatorViewStyleGray;
|
|
||||||
}
|
|
||||||
|
|
||||||
- (void)placeSubviews
|
|
||||||
{
|
|
||||||
[super placeSubviews];
|
|
||||||
|
|
||||||
if (self.loadingView.constraints.count) return;
|
|
||||||
|
|
||||||
// 圈圈
|
|
||||||
CGFloat loadingCenterX = self.mj_w * 0.5;
|
|
||||||
if (!self.isRefreshingTitleHidden) {
|
|
||||||
loadingCenterX -= self.stateLabel.mj_textWidth * 0.5 + self.labelLeftInset;
|
|
||||||
}
|
|
||||||
CGFloat loadingCenterY = self.mj_h * 0.5;
|
|
||||||
self.loadingView.center = CGPointMake(loadingCenterX, loadingCenterY);
|
|
||||||
}
|
|
||||||
|
|
||||||
- (void)setState:(MJRefreshState)state
|
|
||||||
{
|
|
||||||
MJRefreshCheckState
|
|
||||||
|
|
||||||
// 根据状态做事情
|
|
||||||
if (state == MJRefreshStateNoMoreData || state == MJRefreshStateIdle) {
|
|
||||||
[self.loadingView stopAnimating];
|
|
||||||
} else if (state == MJRefreshStateRefreshing) {
|
|
||||||
[self.loadingView startAnimating];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@end
|
|
||||||
@ -1,30 +0,0 @@
|
|||||||
//
|
|
||||||
// MJRefreshAutoStateFooter.h
|
|
||||||
// MJRefresh
|
|
||||||
//
|
|
||||||
// Created by MJ Lee on 15/6/13.
|
|
||||||
// Copyright © 2015年 小码哥. All rights reserved.
|
|
||||||
//
|
|
||||||
|
|
||||||
#if __has_include(<MJRefresh/MJRefreshAutoFooter.h>)
|
|
||||||
#import <MJRefresh/MJRefreshAutoFooter.h>
|
|
||||||
#else
|
|
||||||
#import "MJRefreshAutoFooter.h"
|
|
||||||
#endif
|
|
||||||
|
|
||||||
NS_ASSUME_NONNULL_BEGIN
|
|
||||||
|
|
||||||
@interface MJRefreshAutoStateFooter : MJRefreshAutoFooter
|
|
||||||
/** 文字距离圈圈、箭头的距离 */
|
|
||||||
@property (assign, nonatomic) CGFloat labelLeftInset;
|
|
||||||
/** 显示刷新状态的label */
|
|
||||||
@property (weak, nonatomic, readonly) UILabel *stateLabel;
|
|
||||||
|
|
||||||
/** 设置state状态下的文字 */
|
|
||||||
- (instancetype)setTitle:(NSString *)title forState:(MJRefreshState)state;
|
|
||||||
|
|
||||||
/** 隐藏刷新状态的文字 */
|
|
||||||
@property (assign, nonatomic, getter=isRefreshingTitleHidden) BOOL refreshingTitleHidden;
|
|
||||||
@end
|
|
||||||
|
|
||||||
NS_ASSUME_NONNULL_END
|
|
||||||
@ -1,119 +0,0 @@
|
|||||||
//
|
|
||||||
// MJRefreshAutoStateFooter.m
|
|
||||||
// MJRefresh
|
|
||||||
//
|
|
||||||
// Created by MJ Lee on 15/6/13.
|
|
||||||
// Copyright © 2015年 小码哥. All rights reserved.
|
|
||||||
//
|
|
||||||
|
|
||||||
#import "MJRefreshAutoStateFooter.h"
|
|
||||||
#import "NSBundle+MJRefresh.h"
|
|
||||||
|
|
||||||
@interface MJRefreshAutoFooter (TapTriggerFix)
|
|
||||||
|
|
||||||
- (void)beginRefreshingWithoutValidation;
|
|
||||||
@end
|
|
||||||
|
|
||||||
|
|
||||||
@implementation MJRefreshAutoFooter (TapTriggerFix)
|
|
||||||
|
|
||||||
- (void)beginRefreshingWithoutValidation {
|
|
||||||
[super beginRefreshing];
|
|
||||||
}
|
|
||||||
|
|
||||||
@end
|
|
||||||
|
|
||||||
@interface MJRefreshAutoStateFooter()
|
|
||||||
{
|
|
||||||
/** 显示刷新状态的label */
|
|
||||||
__unsafe_unretained UILabel *_stateLabel;
|
|
||||||
}
|
|
||||||
/** 所有状态对应的文字 */
|
|
||||||
@property (strong, nonatomic) NSMutableDictionary *stateTitles;
|
|
||||||
@end
|
|
||||||
|
|
||||||
@implementation MJRefreshAutoStateFooter
|
|
||||||
#pragma mark - 懒加载
|
|
||||||
- (NSMutableDictionary *)stateTitles
|
|
||||||
{
|
|
||||||
if (!_stateTitles) {
|
|
||||||
self.stateTitles = [NSMutableDictionary dictionary];
|
|
||||||
}
|
|
||||||
return _stateTitles;
|
|
||||||
}
|
|
||||||
|
|
||||||
- (UILabel *)stateLabel
|
|
||||||
{
|
|
||||||
if (!_stateLabel) {
|
|
||||||
[self addSubview:_stateLabel = [UILabel mj_label]];
|
|
||||||
}
|
|
||||||
return _stateLabel;
|
|
||||||
}
|
|
||||||
|
|
||||||
#pragma mark - 公共方法
|
|
||||||
- (instancetype)setTitle:(NSString *)title forState:(MJRefreshState)state
|
|
||||||
{
|
|
||||||
if (title == nil) return self;
|
|
||||||
self.stateTitles[@(state)] = title;
|
|
||||||
self.stateLabel.text = self.stateTitles[@(self.state)];
|
|
||||||
return self;
|
|
||||||
}
|
|
||||||
|
|
||||||
#pragma mark - 私有方法
|
|
||||||
- (void)stateLabelClick
|
|
||||||
{
|
|
||||||
if (self.state == MJRefreshStateIdle) {
|
|
||||||
[super beginRefreshingWithoutValidation];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
- (void)textConfiguration {
|
|
||||||
// 初始化文字
|
|
||||||
[self setTitle:[NSBundle mj_localizedStringForKey:MJRefreshAutoFooterIdleText] forState:MJRefreshStateIdle];
|
|
||||||
[self setTitle:[NSBundle mj_localizedStringForKey:MJRefreshAutoFooterRefreshingText] forState:MJRefreshStateRefreshing];
|
|
||||||
[self setTitle:[NSBundle mj_localizedStringForKey:MJRefreshAutoFooterNoMoreDataText] forState:MJRefreshStateNoMoreData];
|
|
||||||
}
|
|
||||||
|
|
||||||
#pragma mark - 重写父类的方法
|
|
||||||
- (void)prepare
|
|
||||||
{
|
|
||||||
[super prepare];
|
|
||||||
|
|
||||||
// 初始化间距
|
|
||||||
self.labelLeftInset = MJRefreshLabelLeftInset;
|
|
||||||
|
|
||||||
[self textConfiguration];
|
|
||||||
|
|
||||||
// 监听label
|
|
||||||
self.stateLabel.userInteractionEnabled = YES;
|
|
||||||
[self.stateLabel addGestureRecognizer:[[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(stateLabelClick)]];
|
|
||||||
}
|
|
||||||
|
|
||||||
- (void)i18nDidChange {
|
|
||||||
[self textConfiguration];
|
|
||||||
|
|
||||||
[super i18nDidChange];
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
- (void)placeSubviews
|
|
||||||
{
|
|
||||||
[super placeSubviews];
|
|
||||||
|
|
||||||
if (self.stateLabel.constraints.count) return;
|
|
||||||
|
|
||||||
// 状态标签
|
|
||||||
self.stateLabel.frame = self.bounds;
|
|
||||||
}
|
|
||||||
|
|
||||||
- (void)setState:(MJRefreshState)state
|
|
||||||
{
|
|
||||||
MJRefreshCheckState
|
|
||||||
|
|
||||||
if (self.isRefreshingTitleHidden && state == MJRefreshStateRefreshing) {
|
|
||||||
self.stateLabel.text = nil;
|
|
||||||
} else {
|
|
||||||
self.stateLabel.text = self.stateTitles[@(state)];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@end
|
|
||||||
@ -1,25 +0,0 @@
|
|||||||
//
|
|
||||||
// MJRefreshBackGifFooter.h
|
|
||||||
// MJRefresh
|
|
||||||
//
|
|
||||||
// Created by MJ Lee on 15/4/24.
|
|
||||||
// Copyright (c) 2015年 小码哥. All rights reserved.
|
|
||||||
//
|
|
||||||
|
|
||||||
#if __has_include(<MJRefresh/MJRefreshBackStateFooter.h>)
|
|
||||||
#import <MJRefresh/MJRefreshBackStateFooter.h>
|
|
||||||
#else
|
|
||||||
#import "MJRefreshBackStateFooter.h"
|
|
||||||
#endif
|
|
||||||
|
|
||||||
NS_ASSUME_NONNULL_BEGIN
|
|
||||||
|
|
||||||
@interface MJRefreshBackGifFooter : MJRefreshBackStateFooter
|
|
||||||
@property (weak, nonatomic, readonly) UIImageView *gifView;
|
|
||||||
|
|
||||||
/** 设置state状态下的动画图片images 动画持续时间duration*/
|
|
||||||
- (instancetype)setImages:(NSArray *)images duration:(NSTimeInterval)duration forState:(MJRefreshState)state;
|
|
||||||
- (instancetype)setImages:(NSArray *)images forState:(MJRefreshState)state;
|
|
||||||
@end
|
|
||||||
|
|
||||||
NS_ASSUME_NONNULL_END
|
|
||||||
@ -1,132 +0,0 @@
|
|||||||
//
|
|
||||||
// MJRefreshBackGifFooter.m
|
|
||||||
// MJRefresh
|
|
||||||
//
|
|
||||||
// Created by MJ Lee on 15/4/24.
|
|
||||||
// Copyright (c) 2015年 小码哥. All rights reserved.
|
|
||||||
//
|
|
||||||
|
|
||||||
#import "MJRefreshBackGifFooter.h"
|
|
||||||
#import "NSBundle+MJRefresh.h"
|
|
||||||
#import "UIView+MJExtension.h"
|
|
||||||
#import "UIScrollView+MJExtension.h"
|
|
||||||
#import "UIScrollView+MJRefresh.h"
|
|
||||||
|
|
||||||
@interface MJRefreshBackGifFooter()
|
|
||||||
{
|
|
||||||
__unsafe_unretained UIImageView *_gifView;
|
|
||||||
}
|
|
||||||
/** 所有状态对应的动画图片 */
|
|
||||||
@property (strong, nonatomic) NSMutableDictionary *stateImages;
|
|
||||||
/** 所有状态对应的动画时间 */
|
|
||||||
@property (strong, nonatomic) NSMutableDictionary *stateDurations;
|
|
||||||
@end
|
|
||||||
|
|
||||||
@implementation MJRefreshBackGifFooter
|
|
||||||
#pragma mark - 懒加载
|
|
||||||
- (UIImageView *)gifView
|
|
||||||
{
|
|
||||||
if (!_gifView) {
|
|
||||||
UIImageView *gifView = [[UIImageView alloc] init];
|
|
||||||
[self addSubview:_gifView = gifView];
|
|
||||||
}
|
|
||||||
return _gifView;
|
|
||||||
}
|
|
||||||
|
|
||||||
- (NSMutableDictionary *)stateImages
|
|
||||||
{
|
|
||||||
if (!_stateImages) {
|
|
||||||
self.stateImages = [NSMutableDictionary dictionary];
|
|
||||||
}
|
|
||||||
return _stateImages;
|
|
||||||
}
|
|
||||||
|
|
||||||
- (NSMutableDictionary *)stateDurations
|
|
||||||
{
|
|
||||||
if (!_stateDurations) {
|
|
||||||
self.stateDurations = [NSMutableDictionary dictionary];
|
|
||||||
}
|
|
||||||
return _stateDurations;
|
|
||||||
}
|
|
||||||
|
|
||||||
#pragma mark - 公共方法
|
|
||||||
- (instancetype)setImages:(NSArray *)images duration:(NSTimeInterval)duration forState:(MJRefreshState)state
|
|
||||||
{
|
|
||||||
if (images == nil) return self;
|
|
||||||
|
|
||||||
self.stateImages[@(state)] = images;
|
|
||||||
self.stateDurations[@(state)] = @(duration);
|
|
||||||
|
|
||||||
/* 根据图片设置控件的高度 */
|
|
||||||
UIImage *image = [images firstObject];
|
|
||||||
if (image.size.height > self.mj_h) {
|
|
||||||
self.mj_h = image.size.height;
|
|
||||||
}
|
|
||||||
return self;
|
|
||||||
}
|
|
||||||
|
|
||||||
- (instancetype)setImages:(NSArray *)images forState:(MJRefreshState)state
|
|
||||||
{
|
|
||||||
return [self setImages:images duration:images.count * 0.1 forState:state];
|
|
||||||
}
|
|
||||||
|
|
||||||
#pragma mark - 实现父类的方法
|
|
||||||
- (void)prepare
|
|
||||||
{
|
|
||||||
[super prepare];
|
|
||||||
|
|
||||||
// 初始化间距
|
|
||||||
self.labelLeftInset = 20;
|
|
||||||
}
|
|
||||||
|
|
||||||
- (void)setPullingPercent:(CGFloat)pullingPercent
|
|
||||||
{
|
|
||||||
[super setPullingPercent:pullingPercent];
|
|
||||||
NSArray *images = self.stateImages[@(MJRefreshStateIdle)];
|
|
||||||
if (self.state != MJRefreshStateIdle || images.count == 0) return;
|
|
||||||
[self.gifView stopAnimating];
|
|
||||||
NSUInteger index = images.count * pullingPercent;
|
|
||||||
if (index >= images.count) index = images.count - 1;
|
|
||||||
self.gifView.image = images[index];
|
|
||||||
}
|
|
||||||
|
|
||||||
- (void)placeSubviews
|
|
||||||
{
|
|
||||||
[super placeSubviews];
|
|
||||||
|
|
||||||
if (self.gifView.constraints.count) return;
|
|
||||||
|
|
||||||
self.gifView.frame = self.bounds;
|
|
||||||
if (self.stateLabel.hidden) {
|
|
||||||
self.gifView.contentMode = UIViewContentModeCenter;
|
|
||||||
} else {
|
|
||||||
self.gifView.contentMode = UIViewContentModeRight;
|
|
||||||
self.gifView.mj_w = self.mj_w * 0.5 - self.labelLeftInset - self.stateLabel.mj_textWidth * 0.5;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
- (void)setState:(MJRefreshState)state
|
|
||||||
{
|
|
||||||
MJRefreshCheckState
|
|
||||||
|
|
||||||
// 根据状态做事情
|
|
||||||
if (state == MJRefreshStatePulling || state == MJRefreshStateRefreshing) {
|
|
||||||
NSArray *images = self.stateImages[@(state)];
|
|
||||||
if (images.count == 0) return;
|
|
||||||
|
|
||||||
self.gifView.hidden = NO;
|
|
||||||
[self.gifView stopAnimating];
|
|
||||||
if (images.count == 1) { // 单张图片
|
|
||||||
self.gifView.image = [images lastObject];
|
|
||||||
} else { // 多张图片
|
|
||||||
self.gifView.animationImages = images;
|
|
||||||
self.gifView.animationDuration = [self.stateDurations[@(state)] doubleValue];
|
|
||||||
[self.gifView startAnimating];
|
|
||||||
}
|
|
||||||
} else if (state == MJRefreshStateIdle) {
|
|
||||||
self.gifView.hidden = NO;
|
|
||||||
} else if (state == MJRefreshStateNoMoreData) {
|
|
||||||
self.gifView.hidden = YES;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@end
|
|
||||||
@ -1,25 +0,0 @@
|
|||||||
//
|
|
||||||
// MJRefreshBackNormalFooter.h
|
|
||||||
// MJRefresh
|
|
||||||
//
|
|
||||||
// Created by MJ Lee on 15/4/24.
|
|
||||||
// Copyright (c) 2015年 小码哥. All rights reserved.
|
|
||||||
//
|
|
||||||
|
|
||||||
#if __has_include(<MJRefresh/MJRefreshBackStateFooter.h>)
|
|
||||||
#import <MJRefresh/MJRefreshBackStateFooter.h>
|
|
||||||
#else
|
|
||||||
#import "MJRefreshBackStateFooter.h"
|
|
||||||
#endif
|
|
||||||
|
|
||||||
NS_ASSUME_NONNULL_BEGIN
|
|
||||||
|
|
||||||
@interface MJRefreshBackNormalFooter : MJRefreshBackStateFooter
|
|
||||||
@property (weak, nonatomic, readonly) UIImageView *arrowView;
|
|
||||||
@property (weak, nonatomic, readonly) UIActivityIndicatorView *loadingView;
|
|
||||||
|
|
||||||
/** 菊花的样式 */
|
|
||||||
@property (assign, nonatomic) UIActivityIndicatorViewStyle activityIndicatorViewStyle MJRefreshDeprecated("first deprecated in 3.2.2 - Use `loadingView` property");
|
|
||||||
@end
|
|
||||||
|
|
||||||
NS_ASSUME_NONNULL_END
|
|
||||||
@ -1,132 +0,0 @@
|
|||||||
//
|
|
||||||
// MJRefreshBackNormalFooter.m
|
|
||||||
// MJRefresh
|
|
||||||
//
|
|
||||||
// Created by MJ Lee on 15/4/24.
|
|
||||||
// Copyright (c) 2015年 小码哥. All rights reserved.
|
|
||||||
//
|
|
||||||
|
|
||||||
#import "MJRefreshBackNormalFooter.h"
|
|
||||||
#import "NSBundle+MJRefresh.h"
|
|
||||||
#import "UIView+MJExtension.h"
|
|
||||||
|
|
||||||
@interface MJRefreshBackNormalFooter()
|
|
||||||
{
|
|
||||||
__unsafe_unretained UIImageView *_arrowView;
|
|
||||||
}
|
|
||||||
@property (weak, nonatomic) UIActivityIndicatorView *loadingView;
|
|
||||||
@end
|
|
||||||
|
|
||||||
@implementation MJRefreshBackNormalFooter
|
|
||||||
#pragma mark - 懒加载子控件
|
|
||||||
- (UIImageView *)arrowView
|
|
||||||
{
|
|
||||||
if (!_arrowView) {
|
|
||||||
UIImageView *arrowView = [[UIImageView alloc] initWithImage:[NSBundle mj_arrowImage]];
|
|
||||||
[self addSubview:_arrowView = arrowView];
|
|
||||||
}
|
|
||||||
return _arrowView;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
- (UIActivityIndicatorView *)loadingView
|
|
||||||
{
|
|
||||||
if (!_loadingView) {
|
|
||||||
UIActivityIndicatorView *loadingView = [[UIActivityIndicatorView alloc] initWithActivityIndicatorStyle:_activityIndicatorViewStyle];
|
|
||||||
loadingView.hidesWhenStopped = YES;
|
|
||||||
[self addSubview:_loadingView = loadingView];
|
|
||||||
}
|
|
||||||
return _loadingView;
|
|
||||||
}
|
|
||||||
|
|
||||||
- (void)setActivityIndicatorViewStyle:(UIActivityIndicatorViewStyle)activityIndicatorViewStyle
|
|
||||||
{
|
|
||||||
_activityIndicatorViewStyle = activityIndicatorViewStyle;
|
|
||||||
|
|
||||||
[self.loadingView removeFromSuperview];
|
|
||||||
self.loadingView = nil;
|
|
||||||
[self setNeedsLayout];
|
|
||||||
}
|
|
||||||
#pragma mark - 重写父类的方法
|
|
||||||
- (void)prepare
|
|
||||||
{
|
|
||||||
[super prepare];
|
|
||||||
|
|
||||||
#if __IPHONE_OS_VERSION_MAX_ALLOWED >= 130000
|
|
||||||
if (@available(iOS 13.0, *)) {
|
|
||||||
_activityIndicatorViewStyle = UIActivityIndicatorViewStyleMedium;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
_activityIndicatorViewStyle = UIActivityIndicatorViewStyleGray;
|
|
||||||
}
|
|
||||||
|
|
||||||
- (void)placeSubviews
|
|
||||||
{
|
|
||||||
[super placeSubviews];
|
|
||||||
|
|
||||||
// 箭头的中心点
|
|
||||||
CGFloat arrowCenterX = self.mj_w * 0.5;
|
|
||||||
if (!self.stateLabel.hidden) {
|
|
||||||
arrowCenterX -= self.labelLeftInset + self.stateLabel.mj_textWidth * 0.5;
|
|
||||||
}
|
|
||||||
CGFloat arrowCenterY = self.mj_h * 0.5;
|
|
||||||
CGPoint arrowCenter = CGPointMake(arrowCenterX, arrowCenterY);
|
|
||||||
|
|
||||||
// 箭头
|
|
||||||
if (self.arrowView.constraints.count == 0) {
|
|
||||||
self.arrowView.mj_size = self.arrowView.image.size;
|
|
||||||
self.arrowView.center = arrowCenter;
|
|
||||||
}
|
|
||||||
|
|
||||||
// 圈圈
|
|
||||||
if (self.loadingView.constraints.count == 0) {
|
|
||||||
self.loadingView.center = arrowCenter;
|
|
||||||
}
|
|
||||||
|
|
||||||
self.arrowView.tintColor = self.stateLabel.textColor;
|
|
||||||
}
|
|
||||||
|
|
||||||
- (void)setState:(MJRefreshState)state
|
|
||||||
{
|
|
||||||
MJRefreshCheckState
|
|
||||||
|
|
||||||
// 根据状态做事情
|
|
||||||
if (state == MJRefreshStateIdle) {
|
|
||||||
if (oldState == MJRefreshStateRefreshing) {
|
|
||||||
self.arrowView.transform = CGAffineTransformMakeRotation(0.000001 - M_PI);
|
|
||||||
[UIView animateWithDuration:self.slowAnimationDuration animations:^{
|
|
||||||
self.loadingView.alpha = 0.0;
|
|
||||||
} completion:^(BOOL finished) {
|
|
||||||
// 防止动画结束后,状态已经不是MJRefreshStateIdle
|
|
||||||
if (self.state != MJRefreshStateIdle) return;
|
|
||||||
|
|
||||||
self.loadingView.alpha = 1.0;
|
|
||||||
[self.loadingView stopAnimating];
|
|
||||||
|
|
||||||
self.arrowView.hidden = NO;
|
|
||||||
}];
|
|
||||||
} else {
|
|
||||||
self.arrowView.hidden = NO;
|
|
||||||
[self.loadingView stopAnimating];
|
|
||||||
[UIView animateWithDuration:self.fastAnimationDuration animations:^{
|
|
||||||
self.arrowView.transform = CGAffineTransformMakeRotation(0.000001 - M_PI);
|
|
||||||
}];
|
|
||||||
}
|
|
||||||
} else if (state == MJRefreshStatePulling) {
|
|
||||||
self.arrowView.hidden = NO;
|
|
||||||
[self.loadingView stopAnimating];
|
|
||||||
[UIView animateWithDuration:self.fastAnimationDuration animations:^{
|
|
||||||
self.arrowView.transform = CGAffineTransformIdentity;
|
|
||||||
}];
|
|
||||||
} else if (state == MJRefreshStateRefreshing) {
|
|
||||||
self.arrowView.hidden = YES;
|
|
||||||
[self.loadingView startAnimating];
|
|
||||||
} else if (state == MJRefreshStateNoMoreData) {
|
|
||||||
self.arrowView.hidden = YES;
|
|
||||||
[self.loadingView stopAnimating];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@end
|
|
||||||
@ -1,29 +0,0 @@
|
|||||||
//
|
|
||||||
// MJRefreshBackStateFooter.h
|
|
||||||
// MJRefresh
|
|
||||||
//
|
|
||||||
// Created by MJ Lee on 15/6/13.
|
|
||||||
// Copyright © 2015年 小码哥. All rights reserved.
|
|
||||||
//
|
|
||||||
|
|
||||||
#if __has_include(<MJRefresh/MJRefreshBackFooter.h>)
|
|
||||||
#import <MJRefresh/MJRefreshBackFooter.h>
|
|
||||||
#else
|
|
||||||
#import "MJRefreshBackFooter.h"
|
|
||||||
#endif
|
|
||||||
|
|
||||||
NS_ASSUME_NONNULL_BEGIN
|
|
||||||
|
|
||||||
@interface MJRefreshBackStateFooter : MJRefreshBackFooter
|
|
||||||
/** 文字距离圈圈、箭头的距离 */
|
|
||||||
@property (assign, nonatomic) CGFloat labelLeftInset;
|
|
||||||
/** 显示刷新状态的label */
|
|
||||||
@property (weak, nonatomic, readonly) UILabel *stateLabel;
|
|
||||||
/** 设置state状态下的文字 */
|
|
||||||
- (instancetype)setTitle:(NSString *)title forState:(MJRefreshState)state;
|
|
||||||
|
|
||||||
/** 获取state状态下的title */
|
|
||||||
- (NSString *)titleForState:(MJRefreshState)state;
|
|
||||||
@end
|
|
||||||
|
|
||||||
NS_ASSUME_NONNULL_END
|
|
||||||
@ -1,93 +0,0 @@
|
|||||||
//
|
|
||||||
// MJRefreshBackStateFooter.m
|
|
||||||
// MJRefresh
|
|
||||||
//
|
|
||||||
// Created by MJ Lee on 15/6/13.
|
|
||||||
// Copyright © 2015年 小码哥. All rights reserved.
|
|
||||||
//
|
|
||||||
|
|
||||||
#import "MJRefreshBackStateFooter.h"
|
|
||||||
#import "NSBundle+MJRefresh.h"
|
|
||||||
|
|
||||||
@interface MJRefreshBackStateFooter()
|
|
||||||
{
|
|
||||||
/** 显示刷新状态的label */
|
|
||||||
__unsafe_unretained UILabel *_stateLabel;
|
|
||||||
}
|
|
||||||
/** 所有状态对应的文字 */
|
|
||||||
@property (strong, nonatomic) NSMutableDictionary *stateTitles;
|
|
||||||
@end
|
|
||||||
|
|
||||||
@implementation MJRefreshBackStateFooter
|
|
||||||
#pragma mark - 懒加载
|
|
||||||
- (NSMutableDictionary *)stateTitles
|
|
||||||
{
|
|
||||||
if (!_stateTitles) {
|
|
||||||
self.stateTitles = [NSMutableDictionary dictionary];
|
|
||||||
}
|
|
||||||
return _stateTitles;
|
|
||||||
}
|
|
||||||
|
|
||||||
- (UILabel *)stateLabel
|
|
||||||
{
|
|
||||||
if (!_stateLabel) {
|
|
||||||
[self addSubview:_stateLabel = [UILabel mj_label]];
|
|
||||||
}
|
|
||||||
return _stateLabel;
|
|
||||||
}
|
|
||||||
|
|
||||||
#pragma mark - 公共方法
|
|
||||||
- (instancetype)setTitle:(NSString *)title forState:(MJRefreshState)state
|
|
||||||
{
|
|
||||||
if (title == nil) return self;
|
|
||||||
self.stateTitles[@(state)] = title;
|
|
||||||
self.stateLabel.text = self.stateTitles[@(self.state)];
|
|
||||||
return self;
|
|
||||||
}
|
|
||||||
|
|
||||||
- (NSString *)titleForState:(MJRefreshState)state {
|
|
||||||
return self.stateTitles[@(state)];
|
|
||||||
}
|
|
||||||
|
|
||||||
- (void)textConfiguration {
|
|
||||||
// 初始化文字
|
|
||||||
[self setTitle:[NSBundle mj_localizedStringForKey:MJRefreshBackFooterIdleText] forState:MJRefreshStateIdle];
|
|
||||||
[self setTitle:[NSBundle mj_localizedStringForKey:MJRefreshBackFooterPullingText] forState:MJRefreshStatePulling];
|
|
||||||
[self setTitle:[NSBundle mj_localizedStringForKey:MJRefreshBackFooterRefreshingText] forState:MJRefreshStateRefreshing];
|
|
||||||
[self setTitle:[NSBundle mj_localizedStringForKey:MJRefreshBackFooterNoMoreDataText] forState:MJRefreshStateNoMoreData];
|
|
||||||
}
|
|
||||||
|
|
||||||
#pragma mark - 重写父类的方法
|
|
||||||
- (void)prepare
|
|
||||||
{
|
|
||||||
[super prepare];
|
|
||||||
|
|
||||||
// 初始化间距
|
|
||||||
self.labelLeftInset = MJRefreshLabelLeftInset;
|
|
||||||
[self textConfiguration];
|
|
||||||
}
|
|
||||||
|
|
||||||
- (void)i18nDidChange {
|
|
||||||
[self textConfiguration];
|
|
||||||
|
|
||||||
[super i18nDidChange];
|
|
||||||
}
|
|
||||||
|
|
||||||
- (void)placeSubviews
|
|
||||||
{
|
|
||||||
[super placeSubviews];
|
|
||||||
|
|
||||||
if (self.stateLabel.constraints.count) return;
|
|
||||||
|
|
||||||
// 状态标签
|
|
||||||
self.stateLabel.frame = self.bounds;
|
|
||||||
}
|
|
||||||
|
|
||||||
- (void)setState:(MJRefreshState)state
|
|
||||||
{
|
|
||||||
MJRefreshCheckState
|
|
||||||
|
|
||||||
// 设置状态文字
|
|
||||||
self.stateLabel.text = self.stateTitles[@(state)];
|
|
||||||
}
|
|
||||||
@end
|
|
||||||
@ -1,25 +0,0 @@
|
|||||||
//
|
|
||||||
// MJRefreshGifHeader.h
|
|
||||||
// MJRefresh
|
|
||||||
//
|
|
||||||
// Created by MJ Lee on 15/4/24.
|
|
||||||
// Copyright (c) 2015年 小码哥. All rights reserved.
|
|
||||||
//
|
|
||||||
|
|
||||||
#if __has_include(<MJRefresh/MJRefreshStateHeader.h>)
|
|
||||||
#import <MJRefresh/MJRefreshStateHeader.h>
|
|
||||||
#else
|
|
||||||
#import "MJRefreshStateHeader.h"
|
|
||||||
#endif
|
|
||||||
|
|
||||||
NS_ASSUME_NONNULL_BEGIN
|
|
||||||
|
|
||||||
@interface MJRefreshGifHeader : MJRefreshStateHeader
|
|
||||||
@property (weak, nonatomic, readonly) UIImageView *gifView;
|
|
||||||
|
|
||||||
/** 设置state状态下的动画图片images 动画持续时间duration*/
|
|
||||||
- (instancetype)setImages:(NSArray *)images duration:(NSTimeInterval)duration forState:(MJRefreshState)state;
|
|
||||||
- (instancetype)setImages:(NSArray *)images forState:(MJRefreshState)state;
|
|
||||||
@end
|
|
||||||
|
|
||||||
NS_ASSUME_NONNULL_END
|
|
||||||
@ -1,135 +0,0 @@
|
|||||||
//
|
|
||||||
// MJRefreshGifHeader.m
|
|
||||||
// MJRefresh
|
|
||||||
//
|
|
||||||
// Created by MJ Lee on 15/4/24.
|
|
||||||
// Copyright (c) 2015年 小码哥. All rights reserved.
|
|
||||||
//
|
|
||||||
|
|
||||||
#import "MJRefreshGifHeader.h"
|
|
||||||
#import "UIView+MJExtension.h"
|
|
||||||
#import "UIScrollView+MJExtension.h"
|
|
||||||
|
|
||||||
@interface MJRefreshGifHeader()
|
|
||||||
{
|
|
||||||
__unsafe_unretained UIImageView *_gifView;
|
|
||||||
}
|
|
||||||
/** 所有状态对应的动画图片 */
|
|
||||||
@property (strong, nonatomic) NSMutableDictionary *stateImages;
|
|
||||||
/** 所有状态对应的动画时间 */
|
|
||||||
@property (strong, nonatomic) NSMutableDictionary *stateDurations;
|
|
||||||
@end
|
|
||||||
|
|
||||||
@implementation MJRefreshGifHeader
|
|
||||||
#pragma mark - 懒加载
|
|
||||||
- (UIImageView *)gifView
|
|
||||||
{
|
|
||||||
if (!_gifView) {
|
|
||||||
UIImageView *gifView = [[UIImageView alloc] init];
|
|
||||||
[self addSubview:_gifView = gifView];
|
|
||||||
}
|
|
||||||
return _gifView;
|
|
||||||
}
|
|
||||||
|
|
||||||
- (NSMutableDictionary *)stateImages
|
|
||||||
{
|
|
||||||
if (!_stateImages) {
|
|
||||||
self.stateImages = [NSMutableDictionary dictionary];
|
|
||||||
}
|
|
||||||
return _stateImages;
|
|
||||||
}
|
|
||||||
|
|
||||||
- (NSMutableDictionary *)stateDurations
|
|
||||||
{
|
|
||||||
if (!_stateDurations) {
|
|
||||||
self.stateDurations = [NSMutableDictionary dictionary];
|
|
||||||
}
|
|
||||||
return _stateDurations;
|
|
||||||
}
|
|
||||||
|
|
||||||
#pragma mark - 公共方法
|
|
||||||
- (instancetype)setImages:(NSArray *)images duration:(NSTimeInterval)duration forState:(MJRefreshState)state {
|
|
||||||
if (images == nil) return self;
|
|
||||||
|
|
||||||
self.stateImages[@(state)] = images;
|
|
||||||
self.stateDurations[@(state)] = @(duration);
|
|
||||||
|
|
||||||
/* 根据图片设置控件的高度 */
|
|
||||||
UIImage *image = [images firstObject];
|
|
||||||
if (image.size.height > self.mj_h) {
|
|
||||||
self.mj_h = image.size.height;
|
|
||||||
}
|
|
||||||
return self;
|
|
||||||
}
|
|
||||||
|
|
||||||
- (instancetype)setImages:(NSArray *)images forState:(MJRefreshState)state
|
|
||||||
{
|
|
||||||
return [self setImages:images duration:images.count * 0.1 forState:state];
|
|
||||||
}
|
|
||||||
|
|
||||||
#pragma mark - 实现父类的方法
|
|
||||||
- (void)prepare
|
|
||||||
{
|
|
||||||
[super prepare];
|
|
||||||
|
|
||||||
// 初始化间距
|
|
||||||
self.labelLeftInset = 20;
|
|
||||||
}
|
|
||||||
|
|
||||||
- (void)setPullingPercent:(CGFloat)pullingPercent
|
|
||||||
{
|
|
||||||
[super setPullingPercent:pullingPercent];
|
|
||||||
NSArray *images = self.stateImages[@(MJRefreshStateIdle)];
|
|
||||||
if (self.state != MJRefreshStateIdle || images.count == 0) return;
|
|
||||||
// 停止动画
|
|
||||||
[self.gifView stopAnimating];
|
|
||||||
// 设置当前需要显示的图片
|
|
||||||
NSUInteger index = images.count * pullingPercent;
|
|
||||||
if (index >= images.count) index = images.count - 1;
|
|
||||||
self.gifView.image = images[index];
|
|
||||||
}
|
|
||||||
|
|
||||||
- (void)placeSubviews
|
|
||||||
{
|
|
||||||
[super placeSubviews];
|
|
||||||
|
|
||||||
if (self.gifView.constraints.count) return;
|
|
||||||
|
|
||||||
self.gifView.frame = self.bounds;
|
|
||||||
if (self.stateLabel.hidden && self.lastUpdatedTimeLabel.hidden) {
|
|
||||||
self.gifView.contentMode = UIViewContentModeCenter;
|
|
||||||
} else {
|
|
||||||
self.gifView.contentMode = UIViewContentModeRight;
|
|
||||||
|
|
||||||
CGFloat stateWidth = self.stateLabel.mj_textWidth;
|
|
||||||
CGFloat timeWidth = 0.0;
|
|
||||||
if (!self.lastUpdatedTimeLabel.hidden) {
|
|
||||||
timeWidth = self.lastUpdatedTimeLabel.mj_textWidth;
|
|
||||||
}
|
|
||||||
CGFloat textWidth = MAX(stateWidth, timeWidth);
|
|
||||||
self.gifView.mj_w = self.mj_w * 0.5 - textWidth * 0.5 - self.labelLeftInset;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
- (void)setState:(MJRefreshState)state
|
|
||||||
{
|
|
||||||
MJRefreshCheckState
|
|
||||||
|
|
||||||
// 根据状态做事情
|
|
||||||
if (state == MJRefreshStatePulling || state == MJRefreshStateRefreshing) {
|
|
||||||
NSArray *images = self.stateImages[@(state)];
|
|
||||||
if (images.count == 0) return;
|
|
||||||
|
|
||||||
[self.gifView stopAnimating];
|
|
||||||
if (images.count == 1) { // 单张图片
|
|
||||||
self.gifView.image = [images lastObject];
|
|
||||||
} else { // 多张图片
|
|
||||||
self.gifView.animationImages = images;
|
|
||||||
self.gifView.animationDuration = [self.stateDurations[@(state)] doubleValue];
|
|
||||||
[self.gifView startAnimating];
|
|
||||||
}
|
|
||||||
} else if (state == MJRefreshStateIdle) {
|
|
||||||
[self.gifView stopAnimating];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@end
|
|
||||||
@ -1,26 +0,0 @@
|
|||||||
//
|
|
||||||
// MJRefreshNormalHeader.h
|
|
||||||
// MJRefresh
|
|
||||||
//
|
|
||||||
// Created by MJ Lee on 15/4/24.
|
|
||||||
// Copyright (c) 2015年 小码哥. All rights reserved.
|
|
||||||
//
|
|
||||||
|
|
||||||
#if __has_include(<MJRefresh/MJRefreshStateHeader.h>)
|
|
||||||
#import <MJRefresh/MJRefreshStateHeader.h>
|
|
||||||
#else
|
|
||||||
#import "MJRefreshStateHeader.h"
|
|
||||||
#endif
|
|
||||||
|
|
||||||
NS_ASSUME_NONNULL_BEGIN
|
|
||||||
|
|
||||||
@interface MJRefreshNormalHeader : MJRefreshStateHeader
|
|
||||||
@property (weak, nonatomic, readonly) UIImageView *arrowView;
|
|
||||||
@property (weak, nonatomic, readonly) UIActivityIndicatorView *loadingView;
|
|
||||||
|
|
||||||
|
|
||||||
/** 菊花的样式 */
|
|
||||||
@property (assign, nonatomic) UIActivityIndicatorViewStyle activityIndicatorViewStyle MJRefreshDeprecated("first deprecated in 3.2.2 - Use `loadingView` property");
|
|
||||||
@end
|
|
||||||
|
|
||||||
NS_ASSUME_NONNULL_END
|
|
||||||
@ -1,137 +0,0 @@
|
|||||||
//
|
|
||||||
// MJRefreshNormalHeader.m
|
|
||||||
// MJRefresh
|
|
||||||
//
|
|
||||||
// Created by MJ Lee on 15/4/24.
|
|
||||||
// Copyright (c) 2015年 小码哥. All rights reserved.
|
|
||||||
//
|
|
||||||
|
|
||||||
#import "MJRefreshNormalHeader.h"
|
|
||||||
#import "NSBundle+MJRefresh.h"
|
|
||||||
#import "UIScrollView+MJRefresh.h"
|
|
||||||
#import "UIView+MJExtension.h"
|
|
||||||
|
|
||||||
@interface MJRefreshNormalHeader()
|
|
||||||
{
|
|
||||||
__unsafe_unretained UIImageView *_arrowView;
|
|
||||||
}
|
|
||||||
@property (weak, nonatomic) UIActivityIndicatorView *loadingView;
|
|
||||||
@end
|
|
||||||
|
|
||||||
@implementation MJRefreshNormalHeader
|
|
||||||
#pragma mark - 懒加载子控件
|
|
||||||
- (UIImageView *)arrowView
|
|
||||||
{
|
|
||||||
if (!_arrowView) {
|
|
||||||
UIImageView *arrowView = [[UIImageView alloc] initWithImage:[NSBundle mj_arrowImage]];
|
|
||||||
[self addSubview:_arrowView = arrowView];
|
|
||||||
}
|
|
||||||
return _arrowView;
|
|
||||||
}
|
|
||||||
|
|
||||||
- (UIActivityIndicatorView *)loadingView
|
|
||||||
{
|
|
||||||
if (!_loadingView) {
|
|
||||||
UIActivityIndicatorView *loadingView = [[UIActivityIndicatorView alloc] initWithActivityIndicatorStyle:_activityIndicatorViewStyle];
|
|
||||||
loadingView.hidesWhenStopped = YES;
|
|
||||||
[self addSubview:_loadingView = loadingView];
|
|
||||||
}
|
|
||||||
return _loadingView;
|
|
||||||
}
|
|
||||||
|
|
||||||
#pragma mark - 公共方法
|
|
||||||
- (void)setActivityIndicatorViewStyle:(UIActivityIndicatorViewStyle)activityIndicatorViewStyle
|
|
||||||
{
|
|
||||||
_activityIndicatorViewStyle = activityIndicatorViewStyle;
|
|
||||||
|
|
||||||
[self.loadingView removeFromSuperview];
|
|
||||||
self.loadingView = nil;
|
|
||||||
[self setNeedsLayout];
|
|
||||||
}
|
|
||||||
|
|
||||||
#pragma mark - 重写父类的方法
|
|
||||||
- (void)prepare
|
|
||||||
{
|
|
||||||
[super prepare];
|
|
||||||
|
|
||||||
#if __IPHONE_OS_VERSION_MAX_ALLOWED >= 130000
|
|
||||||
if (@available(iOS 13.0, *)) {
|
|
||||||
_activityIndicatorViewStyle = UIActivityIndicatorViewStyleMedium;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
_activityIndicatorViewStyle = UIActivityIndicatorViewStyleGray;
|
|
||||||
}
|
|
||||||
|
|
||||||
- (void)placeSubviews
|
|
||||||
{
|
|
||||||
[super placeSubviews];
|
|
||||||
|
|
||||||
// 箭头的中心点
|
|
||||||
CGFloat arrowCenterX = self.mj_w * 0.5;
|
|
||||||
if (!self.stateLabel.hidden) {
|
|
||||||
CGFloat stateWidth = self.stateLabel.mj_textWidth;
|
|
||||||
CGFloat timeWidth = 0.0;
|
|
||||||
if (!self.lastUpdatedTimeLabel.hidden) {
|
|
||||||
timeWidth = self.lastUpdatedTimeLabel.mj_textWidth;
|
|
||||||
}
|
|
||||||
CGFloat textWidth = MAX(stateWidth, timeWidth);
|
|
||||||
arrowCenterX -= textWidth / 2 + self.labelLeftInset;
|
|
||||||
}
|
|
||||||
CGFloat arrowCenterY = self.mj_h * 0.5;
|
|
||||||
CGPoint arrowCenter = CGPointMake(arrowCenterX, arrowCenterY);
|
|
||||||
|
|
||||||
// 箭头
|
|
||||||
if (self.arrowView.constraints.count == 0) {
|
|
||||||
self.arrowView.mj_size = self.arrowView.image.size;
|
|
||||||
self.arrowView.center = arrowCenter;
|
|
||||||
}
|
|
||||||
|
|
||||||
// 圈圈
|
|
||||||
if (self.loadingView.constraints.count == 0) {
|
|
||||||
self.loadingView.center = arrowCenter;
|
|
||||||
}
|
|
||||||
|
|
||||||
self.arrowView.tintColor = self.stateLabel.textColor;
|
|
||||||
}
|
|
||||||
|
|
||||||
- (void)setState:(MJRefreshState)state
|
|
||||||
{
|
|
||||||
MJRefreshCheckState
|
|
||||||
|
|
||||||
// 根据状态做事情
|
|
||||||
if (state == MJRefreshStateIdle) {
|
|
||||||
if (oldState == MJRefreshStateRefreshing) {
|
|
||||||
self.arrowView.transform = CGAffineTransformIdentity;
|
|
||||||
|
|
||||||
[UIView animateWithDuration:self.slowAnimationDuration animations:^{
|
|
||||||
self.loadingView.alpha = 0.0;
|
|
||||||
} completion:^(BOOL finished) {
|
|
||||||
// 如果执行完动画发现不是idle状态,就直接返回,进入其他状态
|
|
||||||
if (self.state != MJRefreshStateIdle) return;
|
|
||||||
|
|
||||||
self.loadingView.alpha = 1.0;
|
|
||||||
[self.loadingView stopAnimating];
|
|
||||||
self.arrowView.hidden = NO;
|
|
||||||
}];
|
|
||||||
} else {
|
|
||||||
[self.loadingView stopAnimating];
|
|
||||||
self.arrowView.hidden = NO;
|
|
||||||
[UIView animateWithDuration:self.fastAnimationDuration animations:^{
|
|
||||||
self.arrowView.transform = CGAffineTransformIdentity;
|
|
||||||
}];
|
|
||||||
}
|
|
||||||
} else if (state == MJRefreshStatePulling) {
|
|
||||||
[self.loadingView stopAnimating];
|
|
||||||
self.arrowView.hidden = NO;
|
|
||||||
[UIView animateWithDuration:self.fastAnimationDuration animations:^{
|
|
||||||
self.arrowView.transform = CGAffineTransformMakeRotation(0.000001 - M_PI);
|
|
||||||
}];
|
|
||||||
} else if (state == MJRefreshStateRefreshing) {
|
|
||||||
self.loadingView.alpha = 1.0; // 防止refreshing -> idle的动画完毕动作没有被执行
|
|
||||||
[self.loadingView startAnimating];
|
|
||||||
self.arrowView.hidden = YES;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@end
|
|
||||||
@ -1,39 +0,0 @@
|
|||||||
//
|
|
||||||
// MJRefreshStateHeader.h
|
|
||||||
// MJRefresh
|
|
||||||
//
|
|
||||||
// Created by MJ Lee on 15/4/24.
|
|
||||||
// Copyright (c) 2015年 小码哥. All rights reserved.
|
|
||||||
//
|
|
||||||
|
|
||||||
#if __has_include(<MJRefresh/MJRefreshHeader.h>)
|
|
||||||
#import <MJRefresh/MJRefreshHeader.h>
|
|
||||||
#else
|
|
||||||
#import "MJRefreshHeader.h"
|
|
||||||
#endif
|
|
||||||
|
|
||||||
NS_ASSUME_NONNULL_BEGIN
|
|
||||||
|
|
||||||
@interface MJRefreshStateHeader : MJRefreshHeader
|
|
||||||
#pragma mark - 刷新时间相关
|
|
||||||
/** 利用这个block来决定显示的更新时间文字 */
|
|
||||||
@property (copy, nonatomic, nullable) NSString *(^lastUpdatedTimeText)(NSDate * _Nullable lastUpdatedTime);
|
|
||||||
/** 显示上一次刷新时间的label */
|
|
||||||
@property (weak, nonatomic, readonly) UILabel *lastUpdatedTimeLabel;
|
|
||||||
|
|
||||||
#pragma mark - 状态相关
|
|
||||||
/** 文字距离圈圈、箭头的距离 */
|
|
||||||
@property (assign, nonatomic) CGFloat labelLeftInset;
|
|
||||||
/** 显示刷新状态的label */
|
|
||||||
@property (weak, nonatomic, readonly) UILabel *stateLabel;
|
|
||||||
/** 设置state状态下的文字 */
|
|
||||||
- (instancetype)setTitle:(NSString *)title forState:(MJRefreshState)state;
|
|
||||||
@end
|
|
||||||
|
|
||||||
@interface MJRefreshStateHeader (ChainingGrammar)
|
|
||||||
|
|
||||||
- (instancetype)modifyLastUpdatedTimeText:(NSString * (^)(NSDate * _Nullable lastUpdatedTime))handler;
|
|
||||||
|
|
||||||
@end
|
|
||||||
|
|
||||||
NS_ASSUME_NONNULL_END
|
|
||||||
@ -1,191 +0,0 @@
|
|||||||
//
|
|
||||||
// MJRefreshStateHeader.m
|
|
||||||
// MJRefresh
|
|
||||||
//
|
|
||||||
// Created by MJ Lee on 15/4/24.
|
|
||||||
// Copyright (c) 2015年 小码哥. All rights reserved.
|
|
||||||
//
|
|
||||||
|
|
||||||
#import "MJRefreshStateHeader.h"
|
|
||||||
#import "MJRefreshConst.h"
|
|
||||||
#import "NSBundle+MJRefresh.h"
|
|
||||||
#import "UIView+MJExtension.h"
|
|
||||||
#import "UIScrollView+MJExtension.h"
|
|
||||||
|
|
||||||
@interface MJRefreshStateHeader()
|
|
||||||
{
|
|
||||||
/** 显示上一次刷新时间的label */
|
|
||||||
__unsafe_unretained UILabel *_lastUpdatedTimeLabel;
|
|
||||||
/** 显示刷新状态的label */
|
|
||||||
__unsafe_unretained UILabel *_stateLabel;
|
|
||||||
}
|
|
||||||
/** 所有状态对应的文字 */
|
|
||||||
@property (strong, nonatomic) NSMutableDictionary *stateTitles;
|
|
||||||
@end
|
|
||||||
|
|
||||||
@implementation MJRefreshStateHeader
|
|
||||||
#pragma mark - 懒加载
|
|
||||||
- (NSMutableDictionary *)stateTitles
|
|
||||||
{
|
|
||||||
if (!_stateTitles) {
|
|
||||||
self.stateTitles = [NSMutableDictionary dictionary];
|
|
||||||
}
|
|
||||||
return _stateTitles;
|
|
||||||
}
|
|
||||||
|
|
||||||
- (UILabel *)stateLabel
|
|
||||||
{
|
|
||||||
if (!_stateLabel) {
|
|
||||||
[self addSubview:_stateLabel = [UILabel mj_label]];
|
|
||||||
}
|
|
||||||
return _stateLabel;
|
|
||||||
}
|
|
||||||
|
|
||||||
- (UILabel *)lastUpdatedTimeLabel
|
|
||||||
{
|
|
||||||
if (!_lastUpdatedTimeLabel) {
|
|
||||||
[self addSubview:_lastUpdatedTimeLabel = [UILabel mj_label]];
|
|
||||||
}
|
|
||||||
return _lastUpdatedTimeLabel;
|
|
||||||
}
|
|
||||||
|
|
||||||
- (void)setLastUpdatedTimeText:(NSString * _Nonnull (^)(NSDate * _Nullable))lastUpdatedTimeText{
|
|
||||||
_lastUpdatedTimeText = lastUpdatedTimeText;
|
|
||||||
// 重新设置key(重新显示时间)
|
|
||||||
self.lastUpdatedTimeKey = self.lastUpdatedTimeKey;
|
|
||||||
}
|
|
||||||
|
|
||||||
#pragma mark - 公共方法
|
|
||||||
- (instancetype)setTitle:(NSString *)title forState:(MJRefreshState)state
|
|
||||||
{
|
|
||||||
if (title == nil) return self;
|
|
||||||
self.stateTitles[@(state)] = title;
|
|
||||||
self.stateLabel.text = self.stateTitles[@(self.state)];
|
|
||||||
return self;
|
|
||||||
}
|
|
||||||
|
|
||||||
#pragma mark key的处理
|
|
||||||
- (void)setLastUpdatedTimeKey:(NSString *)lastUpdatedTimeKey
|
|
||||||
{
|
|
||||||
[super setLastUpdatedTimeKey:lastUpdatedTimeKey];
|
|
||||||
|
|
||||||
// 如果label隐藏了,就不用再处理
|
|
||||||
if (self.lastUpdatedTimeLabel.hidden) return;
|
|
||||||
|
|
||||||
NSDate *lastUpdatedTime = [[NSUserDefaults standardUserDefaults] objectForKey:lastUpdatedTimeKey];
|
|
||||||
|
|
||||||
// 如果有block
|
|
||||||
if (self.lastUpdatedTimeText) {
|
|
||||||
self.lastUpdatedTimeLabel.text = self.lastUpdatedTimeText(lastUpdatedTime);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (lastUpdatedTime) {
|
|
||||||
// 1.获得年月日
|
|
||||||
NSCalendar *calendar = [NSCalendar calendarWithIdentifier:NSCalendarIdentifierGregorian];
|
|
||||||
NSUInteger unitFlags = NSCalendarUnitYear| NSCalendarUnitMonth | NSCalendarUnitDay | NSCalendarUnitHour | NSCalendarUnitMinute;
|
|
||||||
NSDateComponents *cmp1 = [calendar components:unitFlags fromDate:lastUpdatedTime];
|
|
||||||
NSDateComponents *cmp2 = [calendar components:unitFlags fromDate:[NSDate date]];
|
|
||||||
|
|
||||||
// 2.格式化日期
|
|
||||||
NSDateFormatter *formatter = [[NSDateFormatter alloc] init];
|
|
||||||
BOOL isToday = NO;
|
|
||||||
if ([cmp1 day] == [cmp2 day]) { // 今天
|
|
||||||
formatter.dateFormat = @" HH:mm";
|
|
||||||
isToday = YES;
|
|
||||||
} else if ([cmp1 year] == [cmp2 year]) { // 今年
|
|
||||||
formatter.dateFormat = @"MM-dd HH:mm";
|
|
||||||
} else {
|
|
||||||
formatter.dateFormat = @"yyyy-MM-dd HH:mm";
|
|
||||||
}
|
|
||||||
NSString *time = [formatter stringFromDate:lastUpdatedTime];
|
|
||||||
|
|
||||||
// 3.显示日期
|
|
||||||
self.lastUpdatedTimeLabel.text = [NSString stringWithFormat:@"%@%@%@",
|
|
||||||
[NSBundle mj_localizedStringForKey:MJRefreshHeaderLastTimeText],
|
|
||||||
isToday ? [NSBundle mj_localizedStringForKey:MJRefreshHeaderDateTodayText] : @"",
|
|
||||||
time];
|
|
||||||
} else {
|
|
||||||
self.lastUpdatedTimeLabel.text = [NSString stringWithFormat:@"%@%@",
|
|
||||||
[NSBundle mj_localizedStringForKey:MJRefreshHeaderLastTimeText],
|
|
||||||
[NSBundle mj_localizedStringForKey:MJRefreshHeaderNoneLastDateText]];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
- (void)textConfiguration {
|
|
||||||
// 初始化文字
|
|
||||||
[self setTitle:[NSBundle mj_localizedStringForKey:MJRefreshHeaderIdleText] forState:MJRefreshStateIdle];
|
|
||||||
[self setTitle:[NSBundle mj_localizedStringForKey:MJRefreshHeaderPullingText] forState:MJRefreshStatePulling];
|
|
||||||
[self setTitle:[NSBundle mj_localizedStringForKey:MJRefreshHeaderRefreshingText] forState:MJRefreshStateRefreshing];
|
|
||||||
self.lastUpdatedTimeKey = MJRefreshHeaderLastUpdatedTimeKey;
|
|
||||||
}
|
|
||||||
|
|
||||||
#pragma mark - 覆盖父类的方法
|
|
||||||
- (void)prepare
|
|
||||||
{
|
|
||||||
[super prepare];
|
|
||||||
|
|
||||||
// 初始化间距
|
|
||||||
self.labelLeftInset = MJRefreshLabelLeftInset;
|
|
||||||
[self textConfiguration];
|
|
||||||
}
|
|
||||||
|
|
||||||
- (void)i18nDidChange {
|
|
||||||
[self textConfiguration];
|
|
||||||
|
|
||||||
[super i18nDidChange];
|
|
||||||
}
|
|
||||||
|
|
||||||
- (void)placeSubviews
|
|
||||||
{
|
|
||||||
[super placeSubviews];
|
|
||||||
|
|
||||||
if (self.stateLabel.hidden) return;
|
|
||||||
|
|
||||||
BOOL noConstrainsOnStatusLabel = self.stateLabel.constraints.count == 0;
|
|
||||||
|
|
||||||
if (self.lastUpdatedTimeLabel.hidden) {
|
|
||||||
// 状态
|
|
||||||
if (noConstrainsOnStatusLabel) self.stateLabel.frame = self.bounds;
|
|
||||||
} else {
|
|
||||||
CGFloat stateLabelH = self.mj_h * 0.5;
|
|
||||||
// 状态
|
|
||||||
if (noConstrainsOnStatusLabel) {
|
|
||||||
self.stateLabel.mj_x = 0;
|
|
||||||
self.stateLabel.mj_y = 0;
|
|
||||||
self.stateLabel.mj_w = self.mj_w;
|
|
||||||
self.stateLabel.mj_h = stateLabelH;
|
|
||||||
}
|
|
||||||
|
|
||||||
// 更新时间
|
|
||||||
if (self.lastUpdatedTimeLabel.constraints.count == 0) {
|
|
||||||
self.lastUpdatedTimeLabel.mj_x = 0;
|
|
||||||
self.lastUpdatedTimeLabel.mj_y = stateLabelH;
|
|
||||||
self.lastUpdatedTimeLabel.mj_w = self.mj_w;
|
|
||||||
self.lastUpdatedTimeLabel.mj_h = self.mj_h - self.lastUpdatedTimeLabel.mj_y;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
- (void)setState:(MJRefreshState)state
|
|
||||||
{
|
|
||||||
MJRefreshCheckState
|
|
||||||
|
|
||||||
// 设置状态文字
|
|
||||||
self.stateLabel.text = self.stateTitles[@(state)];
|
|
||||||
|
|
||||||
// 重新设置key(重新显示时间)
|
|
||||||
self.lastUpdatedTimeKey = self.lastUpdatedTimeKey;
|
|
||||||
}
|
|
||||||
@end
|
|
||||||
|
|
||||||
#pragma mark - <<< 为 Swift 扩展链式语法 >>> -
|
|
||||||
@implementation MJRefreshStateHeader (ChainingGrammar)
|
|
||||||
|
|
||||||
- (instancetype)modifyLastUpdatedTimeText:(NSString * _Nonnull (^)(NSDate * _Nullable))handler {
|
|
||||||
self.lastUpdatedTimeText = handler;
|
|
||||||
return self;
|
|
||||||
}
|
|
||||||
|
|
||||||
@end
|
|
||||||
@ -1,23 +0,0 @@
|
|||||||
//
|
|
||||||
// MJRefreshNormalTrailer.h
|
|
||||||
// MJRefresh
|
|
||||||
//
|
|
||||||
// Created by kinarobin on 2020/5/3.
|
|
||||||
// Copyright © 2020 小码哥. All rights reserved.
|
|
||||||
//
|
|
||||||
|
|
||||||
#if __has_include(<MJRefresh/MJRefreshStateTrailer.h>)
|
|
||||||
#import <MJRefresh/MJRefreshStateTrailer.h>
|
|
||||||
#else
|
|
||||||
#import "MJRefreshStateTrailer.h"
|
|
||||||
#endif
|
|
||||||
|
|
||||||
NS_ASSUME_NONNULL_BEGIN
|
|
||||||
|
|
||||||
@interface MJRefreshNormalTrailer : MJRefreshStateTrailer
|
|
||||||
|
|
||||||
@property (weak, nonatomic, readonly) UIImageView *arrowView;
|
|
||||||
|
|
||||||
@end
|
|
||||||
|
|
||||||
NS_ASSUME_NONNULL_END
|
|
||||||
@ -1,80 +0,0 @@
|
|||||||
//
|
|
||||||
// MJRefreshNormalTrailer.m
|
|
||||||
// MJRefresh
|
|
||||||
//
|
|
||||||
// Created by kinarobin on 2020/5/3.
|
|
||||||
// Copyright © 2020 小码哥. All rights reserved.
|
|
||||||
//
|
|
||||||
|
|
||||||
#import "MJRefreshNormalTrailer.h"
|
|
||||||
#import "NSBundle+MJRefresh.h"
|
|
||||||
#import "UIView+MJExtension.h"
|
|
||||||
|
|
||||||
@interface MJRefreshNormalTrailer() {
|
|
||||||
__unsafe_unretained UIImageView *_arrowView;
|
|
||||||
}
|
|
||||||
@end
|
|
||||||
|
|
||||||
@implementation MJRefreshNormalTrailer
|
|
||||||
#pragma mark - 懒加载子控件
|
|
||||||
- (UIImageView *)arrowView {
|
|
||||||
if (!_arrowView) {
|
|
||||||
UIImageView *arrowView = [[UIImageView alloc] initWithImage:[NSBundle mj_trailArrowImage]];
|
|
||||||
[self addSubview:_arrowView = arrowView];
|
|
||||||
}
|
|
||||||
return _arrowView;
|
|
||||||
}
|
|
||||||
|
|
||||||
- (void)placeSubviews {
|
|
||||||
[super placeSubviews];
|
|
||||||
|
|
||||||
CGSize arrowSize = self.arrowView.image.size;
|
|
||||||
// 箭头的中心点
|
|
||||||
CGPoint selfCenter = CGPointMake(self.mj_w * 0.5, self.mj_h * 0.5);
|
|
||||||
CGPoint arrowCenter = CGPointMake(arrowSize.width * 0.5 + 5, self.mj_h * 0.5);
|
|
||||||
BOOL stateHidden = self.stateLabel.isHidden;
|
|
||||||
|
|
||||||
if (self.arrowView.constraints.count == 0) {
|
|
||||||
self.arrowView.mj_size = self.arrowView.image.size;
|
|
||||||
self.arrowView.center = stateHidden ? selfCenter : arrowCenter ;
|
|
||||||
}
|
|
||||||
self.arrowView.tintColor = self.stateLabel.textColor;
|
|
||||||
|
|
||||||
if (stateHidden) return;
|
|
||||||
|
|
||||||
BOOL noConstrainsOnStatusLabel = self.stateLabel.constraints.count == 0;
|
|
||||||
CGFloat stateLabelW = ceil(self.stateLabel.font.pointSize);
|
|
||||||
// 状态
|
|
||||||
if (noConstrainsOnStatusLabel) {
|
|
||||||
BOOL arrowHidden = self.arrowView.isHidden;
|
|
||||||
CGFloat stateCenterX = (self.mj_w + arrowSize.width) * 0.5;
|
|
||||||
self.stateLabel.center = arrowHidden ? selfCenter : CGPointMake(stateCenterX, self.mj_h * 0.5);
|
|
||||||
self.stateLabel.mj_size = CGSizeMake(stateLabelW, self.mj_h) ;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
- (void)setState:(MJRefreshState)state {
|
|
||||||
MJRefreshCheckState
|
|
||||||
// 根据状态做事情
|
|
||||||
if (state == MJRefreshStateIdle) {
|
|
||||||
if (oldState == MJRefreshStateRefreshing) {
|
|
||||||
[UIView animateWithDuration:self.fastAnimationDuration animations:^{
|
|
||||||
self.arrowView.transform = CGAffineTransformMakeRotation(M_PI);
|
|
||||||
} completion:^(BOOL finished) {
|
|
||||||
self.arrowView.transform = CGAffineTransformIdentity;
|
|
||||||
}];
|
|
||||||
} else {
|
|
||||||
[UIView animateWithDuration:self.fastAnimationDuration animations:^{
|
|
||||||
self.arrowView.transform = CGAffineTransformIdentity;
|
|
||||||
}];
|
|
||||||
}
|
|
||||||
} else if (state == MJRefreshStatePulling) {
|
|
||||||
[UIView animateWithDuration:self.fastAnimationDuration animations:^{
|
|
||||||
self.arrowView.transform = CGAffineTransformMakeRotation(M_PI);
|
|
||||||
}];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@end
|
|
||||||
@ -1,28 +0,0 @@
|
|||||||
//
|
|
||||||
// MJRefreshStateTrailer.h
|
|
||||||
// MJRefresh
|
|
||||||
//
|
|
||||||
// Created by kinarobin on 2020/5/3.
|
|
||||||
// Copyright © 2020 小码哥. All rights reserved.
|
|
||||||
//
|
|
||||||
|
|
||||||
#if __has_include(<MJRefresh/MJRefreshTrailer.h>)
|
|
||||||
#import <MJRefresh/MJRefreshTrailer.h>
|
|
||||||
#else
|
|
||||||
#import "MJRefreshTrailer.h"
|
|
||||||
#endif
|
|
||||||
|
|
||||||
NS_ASSUME_NONNULL_BEGIN
|
|
||||||
|
|
||||||
|
|
||||||
@interface MJRefreshStateTrailer : MJRefreshTrailer
|
|
||||||
|
|
||||||
#pragma mark - 状态相关
|
|
||||||
/** 显示刷新状态的label */
|
|
||||||
@property (weak, nonatomic, readonly) UILabel *stateLabel;
|
|
||||||
/** 设置state状态下的文字 */
|
|
||||||
- (instancetype)setTitle:(NSString *)title forState:(MJRefreshState)state;
|
|
||||||
|
|
||||||
@end
|
|
||||||
|
|
||||||
NS_ASSUME_NONNULL_END
|
|
||||||
@ -1,87 +0,0 @@
|
|||||||
//
|
|
||||||
// MJRefreshStateTrailer.m
|
|
||||||
// MJRefresh
|
|
||||||
//
|
|
||||||
// Created by kinarobin on 2020/5/3.
|
|
||||||
// Copyright © 2020 小码哥. All rights reserved.
|
|
||||||
//
|
|
||||||
|
|
||||||
#import "MJRefreshStateTrailer.h"
|
|
||||||
#import "NSBundle+MJRefresh.h"
|
|
||||||
#import "UIView+MJExtension.h"
|
|
||||||
|
|
||||||
@interface MJRefreshStateTrailer() {
|
|
||||||
/** 显示刷新状态的label */
|
|
||||||
__unsafe_unretained UILabel *_stateLabel;
|
|
||||||
}
|
|
||||||
/** 所有状态对应的文字 */
|
|
||||||
@property (strong, nonatomic) NSMutableDictionary *stateTitles;
|
|
||||||
@end
|
|
||||||
|
|
||||||
@implementation MJRefreshStateTrailer
|
|
||||||
#pragma mark - 懒加载
|
|
||||||
- (NSMutableDictionary *)stateTitles {
|
|
||||||
if (!_stateTitles) {
|
|
||||||
self.stateTitles = [NSMutableDictionary dictionary];
|
|
||||||
}
|
|
||||||
return _stateTitles;
|
|
||||||
}
|
|
||||||
|
|
||||||
- (UILabel *)stateLabel {
|
|
||||||
if (!_stateLabel) {
|
|
||||||
UILabel *stateLabel = [UILabel mj_label];
|
|
||||||
stateLabel.numberOfLines = 0;
|
|
||||||
[self addSubview:_stateLabel = stateLabel];
|
|
||||||
}
|
|
||||||
return _stateLabel;
|
|
||||||
}
|
|
||||||
|
|
||||||
#pragma mark - 公共方法
|
|
||||||
- (instancetype)setTitle:(NSString *)title forState:(MJRefreshState)state {
|
|
||||||
if (title == nil) return self;
|
|
||||||
self.stateTitles[@(state)] = title;
|
|
||||||
self.stateLabel.text = self.stateTitles[@(self.state)];
|
|
||||||
return self;
|
|
||||||
}
|
|
||||||
|
|
||||||
- (void)textConfiguration {
|
|
||||||
// 初始化文字
|
|
||||||
[self setTitle:[NSBundle mj_localizedStringForKey:MJRefreshTrailerIdleText] forState:MJRefreshStateIdle];
|
|
||||||
[self setTitle:[NSBundle mj_localizedStringForKey:MJRefreshTrailerPullingText] forState:MJRefreshStatePulling];
|
|
||||||
[self setTitle:[NSBundle mj_localizedStringForKey:MJRefreshTrailerPullingText] forState:MJRefreshStateRefreshing];
|
|
||||||
}
|
|
||||||
|
|
||||||
#pragma mark - 覆盖父类的方法
|
|
||||||
- (void)prepare {
|
|
||||||
[super prepare];
|
|
||||||
|
|
||||||
[self textConfiguration];
|
|
||||||
}
|
|
||||||
|
|
||||||
- (void)i18nDidChange {
|
|
||||||
[self textConfiguration];
|
|
||||||
|
|
||||||
[super i18nDidChange];
|
|
||||||
}
|
|
||||||
|
|
||||||
- (void)setState:(MJRefreshState)state {
|
|
||||||
MJRefreshCheckState
|
|
||||||
// 设置状态文字
|
|
||||||
self.stateLabel.text = self.stateTitles[@(state)];
|
|
||||||
}
|
|
||||||
|
|
||||||
- (void)placeSubviews {
|
|
||||||
[super placeSubviews];
|
|
||||||
|
|
||||||
if (self.stateLabel.hidden) return;
|
|
||||||
|
|
||||||
BOOL noConstrainsOnStatusLabel = self.stateLabel.constraints.count == 0;
|
|
||||||
CGFloat stateLabelW = ceil(self.stateLabel.font.pointSize);
|
|
||||||
// 状态
|
|
||||||
if (noConstrainsOnStatusLabel) {
|
|
||||||
self.stateLabel.center = CGPointMake(self.mj_w * 0.5, self.mj_h * 0.5);
|
|
||||||
self.stateLabel.mj_size = CGSizeMake(stateLabelW, self.mj_h) ;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@end
|
|
||||||
BIN
Pods/MJRefresh/MJRefresh/MJRefresh.bundle/arrow@2x.png
generated
BIN
Pods/MJRefresh/MJRefresh/MJRefresh.bundle/arrow@2x.png
generated
Binary file not shown.
|
Before Width: | Height: | Size: 1.0 KiB |
Binary file not shown.
@ -1,16 +0,0 @@
|
|||||||
"MJRefreshHeaderIdleText" = "아래로 당겨 새로고침";
|
|
||||||
"MJRefreshHeaderPullingText" = "놓으면 새로고침";
|
|
||||||
"MJRefreshHeaderRefreshingText" = "로딩중...";
|
|
||||||
|
|
||||||
"MJRefreshAutoFooterIdleText" = "탭 또는 위로 당겨 로드함";
|
|
||||||
"MJRefreshAutoFooterRefreshingText" = "로딩중...";
|
|
||||||
"MJRefreshAutoFooterNoMoreDataText" = "더이상 데이터 없음";
|
|
||||||
|
|
||||||
"MJRefreshBackFooterIdleText" = "위로 당겨 더 로드 가능";
|
|
||||||
"MJRefreshBackFooterPullingText" = "놓으면 더 로드됨.";
|
|
||||||
"MJRefreshBackFooterRefreshingText" = "로딩중...";
|
|
||||||
"MJRefreshBackFooterNoMoreDataText" = "더이상 데이터 없음";
|
|
||||||
|
|
||||||
"MJRefreshHeaderLastTimeText" = "마지막 업데이트: ";
|
|
||||||
"MJRefreshHeaderDateTodayText" = "오늘";
|
|
||||||
"MJRefreshHeaderNoneLastDateText" = "기록 없음";
|
|
||||||
Binary file not shown.
Binary file not shown.
|
Before Width: | Height: | Size: 2.3 KiB |
Binary file not shown.
Binary file not shown.
@ -1,19 +0,0 @@
|
|||||||
"MJRefreshHeaderIdleText" = "下拉可以刷新";
|
|
||||||
"MJRefreshHeaderPullingText" = "鬆開立即刷新";
|
|
||||||
"MJRefreshHeaderRefreshingText" = "正在刷新數據中...";
|
|
||||||
|
|
||||||
"MJRefreshTrailerIdleText" = "滑動查看圖文詳情";
|
|
||||||
"MJRefreshTrailerPullingText" = "釋放查看圖文詳情";
|
|
||||||
|
|
||||||
"MJRefreshAutoFooterIdleText" = "點擊或上拉加載更多";
|
|
||||||
"MJRefreshAutoFooterRefreshingText" = "正在加載更多的數據...";
|
|
||||||
"MJRefreshAutoFooterNoMoreDataText" = "已經全部加載完畢";
|
|
||||||
|
|
||||||
"MJRefreshBackFooterIdleText" = "上拉可以加載更多";
|
|
||||||
"MJRefreshBackFooterPullingText" = "鬆開立即加載更多";
|
|
||||||
"MJRefreshBackFooterRefreshingText" = "正在加載更多的數據...";
|
|
||||||
"MJRefreshBackFooterNoMoreDataText" = "已經全部加載完畢";
|
|
||||||
|
|
||||||
"MJRefreshHeaderLastTimeText" = "最後更新:";
|
|
||||||
"MJRefreshHeaderDateTodayText" = "今天";
|
|
||||||
"MJRefreshHeaderNoneLastDateText" = "無記錄";
|
|
||||||
42
Pods/MJRefresh/MJRefresh/MJRefresh.h
generated
42
Pods/MJRefresh/MJRefresh/MJRefresh.h
generated
@ -1,42 +0,0 @@
|
|||||||
// 代码地址: https://github.com/CoderMJLee/MJRefresh
|
|
||||||
|
|
||||||
#import <Foundation/Foundation.h>
|
|
||||||
|
|
||||||
#if __has_include(<MJRefresh/MJRefresh.h>)
|
|
||||||
FOUNDATION_EXPORT double MJRefreshVersionNumber;
|
|
||||||
FOUNDATION_EXPORT const unsigned char MJRefreshVersionString[];
|
|
||||||
|
|
||||||
#import <MJRefresh/UIScrollView+MJRefresh.h>
|
|
||||||
#import <MJRefresh/UIScrollView+MJExtension.h>
|
|
||||||
#import <MJRefresh/UIView+MJExtension.h>
|
|
||||||
|
|
||||||
#import <MJRefresh/MJRefreshNormalHeader.h>
|
|
||||||
#import <MJRefresh/MJRefreshGifHeader.h>
|
|
||||||
|
|
||||||
#import <MJRefresh/MJRefreshBackNormalFooter.h>
|
|
||||||
#import <MJRefresh/MJRefreshBackGifFooter.h>
|
|
||||||
#import <MJRefresh/MJRefreshAutoNormalFooter.h>
|
|
||||||
#import <MJRefresh/MJRefreshAutoGifFooter.h>
|
|
||||||
|
|
||||||
#import <MJRefresh/MJRefreshNormalTrailer.h>
|
|
||||||
#import <MJRefresh/MJRefreshConfig.h>
|
|
||||||
#import <MJRefresh/NSBundle+MJRefresh.h>
|
|
||||||
#import <MJRefresh/MJRefreshConst.h>
|
|
||||||
#else
|
|
||||||
#import "UIScrollView+MJRefresh.h"
|
|
||||||
#import "UIScrollView+MJExtension.h"
|
|
||||||
#import "UIView+MJExtension.h"
|
|
||||||
|
|
||||||
#import "MJRefreshNormalHeader.h"
|
|
||||||
#import "MJRefreshGifHeader.h"
|
|
||||||
|
|
||||||
#import "MJRefreshBackNormalFooter.h"
|
|
||||||
#import "MJRefreshBackGifFooter.h"
|
|
||||||
#import "MJRefreshAutoNormalFooter.h"
|
|
||||||
#import "MJRefreshAutoGifFooter.h"
|
|
||||||
|
|
||||||
#import "MJRefreshNormalTrailer.h"
|
|
||||||
#import "MJRefreshConfig.h"
|
|
||||||
#import "NSBundle+MJRefresh.h"
|
|
||||||
#import "MJRefreshConst.h"
|
|
||||||
#endif
|
|
||||||
36
Pods/MJRefresh/MJRefresh/MJRefreshConfig.h
generated
36
Pods/MJRefresh/MJRefresh/MJRefreshConfig.h
generated
@ -1,36 +0,0 @@
|
|||||||
//
|
|
||||||
// MJRefreshConfig.h
|
|
||||||
//
|
|
||||||
// Created by Frank on 2018/11/27.
|
|
||||||
// Copyright © 2018 小码哥. All rights reserved.
|
|
||||||
//
|
|
||||||
|
|
||||||
#import <Foundation/Foundation.h>
|
|
||||||
|
|
||||||
NS_ASSUME_NONNULL_BEGIN
|
|
||||||
|
|
||||||
@interface MJRefreshConfig : NSObject
|
|
||||||
|
|
||||||
/** 默认使用的语言版本, 默认为 nil. 将随系统的语言自动改变 */
|
|
||||||
@property (copy, nonatomic, nullable) NSString *languageCode;
|
|
||||||
|
|
||||||
/** 默认使用的语言资源文件名, 默认为 nil, 即默认的 Localizable.strings.
|
|
||||||
|
|
||||||
- Attention: 文件名不包含后缀.strings
|
|
||||||
*/
|
|
||||||
@property (copy, nonatomic, nullable) NSString *i18nFilename;
|
|
||||||
/** i18n 多语言资源加载自定义 Bundle.
|
|
||||||
|
|
||||||
- Attention: 默认为 nil 采用内置逻辑. 这里设置后将忽略内置逻辑的多语言模式, 采用自定义的多语言 bundle
|
|
||||||
*/
|
|
||||||
@property (nonatomic, nullable) NSBundle *i18nBundle;
|
|
||||||
|
|
||||||
/** Singleton Config instance */
|
|
||||||
@property (class, nonatomic, readonly) MJRefreshConfig *defaultConfig;
|
|
||||||
|
|
||||||
- (instancetype)init NS_UNAVAILABLE;
|
|
||||||
+ (instancetype)new NS_UNAVAILABLE;
|
|
||||||
|
|
||||||
@end
|
|
||||||
|
|
||||||
NS_ASSUME_NONNULL_END
|
|
||||||
42
Pods/MJRefresh/MJRefresh/MJRefreshConfig.m
generated
42
Pods/MJRefresh/MJRefresh/MJRefreshConfig.m
generated
@ -1,42 +0,0 @@
|
|||||||
//
|
|
||||||
// MJRefreshConfig.m
|
|
||||||
//
|
|
||||||
// Created by Frank on 2018/11/27.
|
|
||||||
// Copyright © 2018 小码哥. All rights reserved.
|
|
||||||
//
|
|
||||||
|
|
||||||
#import "MJRefreshConfig.h"
|
|
||||||
#import "MJRefreshConst.h"
|
|
||||||
#import "NSBundle+MJRefresh.h"
|
|
||||||
|
|
||||||
@interface MJRefreshConfig (Bundle)
|
|
||||||
|
|
||||||
+ (void)resetLanguageResourceCache;
|
|
||||||
|
|
||||||
@end
|
|
||||||
|
|
||||||
@implementation MJRefreshConfig
|
|
||||||
|
|
||||||
static MJRefreshConfig *mj_RefreshConfig = nil;
|
|
||||||
|
|
||||||
+ (instancetype)defaultConfig {
|
|
||||||
static dispatch_once_t onceToken;
|
|
||||||
dispatch_once(&onceToken, ^{
|
|
||||||
mj_RefreshConfig = [[self alloc] init];
|
|
||||||
});
|
|
||||||
return mj_RefreshConfig;
|
|
||||||
}
|
|
||||||
|
|
||||||
- (void)setLanguageCode:(NSString *)languageCode {
|
|
||||||
if ([languageCode isEqualToString:_languageCode]) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
_languageCode = languageCode;
|
|
||||||
// 重置语言资源
|
|
||||||
[MJRefreshConfig resetLanguageResourceCache];
|
|
||||||
[NSNotificationCenter.defaultCenter
|
|
||||||
postNotificationName:MJRefreshDidChangeLanguageNotification object:self];
|
|
||||||
}
|
|
||||||
|
|
||||||
@end
|
|
||||||
115
Pods/MJRefresh/MJRefresh/MJRefreshConst.h
generated
115
Pods/MJRefresh/MJRefresh/MJRefreshConst.h
generated
@ -1,115 +0,0 @@
|
|||||||
// 代码地址: https://github.com/CoderMJLee/MJRefresh
|
|
||||||
#import <UIKit/UIKit.h>
|
|
||||||
#import <objc/message.h>
|
|
||||||
#import <objc/runtime.h>
|
|
||||||
|
|
||||||
// 弱引用
|
|
||||||
#define MJWeakSelf __weak typeof(self) weakSelf = self;
|
|
||||||
|
|
||||||
// 日志输出
|
|
||||||
#ifdef DEBUG
|
|
||||||
#define MJRefreshLog(...) NSLog(__VA_ARGS__)
|
|
||||||
#else
|
|
||||||
#define MJRefreshLog(...)
|
|
||||||
#endif
|
|
||||||
|
|
||||||
// 过期提醒
|
|
||||||
#define MJRefreshDeprecated(DESCRIPTION) __attribute__((deprecated(DESCRIPTION)))
|
|
||||||
|
|
||||||
// 运行时objc_msgSend
|
|
||||||
#define MJRefreshMsgSend(...) ((void (*)(void *, SEL, UIView *))objc_msgSend)(__VA_ARGS__)
|
|
||||||
#define MJRefreshMsgTarget(target) (__bridge void *)(target)
|
|
||||||
|
|
||||||
// RGB颜色
|
|
||||||
#define MJRefreshColor(r, g, b) [UIColor colorWithRed:(r)/255.0 green:(g)/255.0 blue:(b)/255.0 alpha:1.0]
|
|
||||||
|
|
||||||
// 文字颜色
|
|
||||||
#define MJRefreshLabelTextColor MJRefreshColor(90, 90, 90)
|
|
||||||
|
|
||||||
// 字体大小
|
|
||||||
#define MJRefreshLabelFont [UIFont boldSystemFontOfSize:14]
|
|
||||||
|
|
||||||
// 常量
|
|
||||||
UIKIT_EXTERN const CGFloat MJRefreshLabelLeftInset;
|
|
||||||
UIKIT_EXTERN const CGFloat MJRefreshHeaderHeight;
|
|
||||||
UIKIT_EXTERN const CGFloat MJRefreshFooterHeight;
|
|
||||||
UIKIT_EXTERN const CGFloat MJRefreshTrailWidth;
|
|
||||||
UIKIT_EXTERN const CGFloat MJRefreshFastAnimationDuration;
|
|
||||||
UIKIT_EXTERN const CGFloat MJRefreshSlowAnimationDuration;
|
|
||||||
|
|
||||||
|
|
||||||
UIKIT_EXTERN NSString *const MJRefreshKeyPathContentOffset;
|
|
||||||
UIKIT_EXTERN NSString *const MJRefreshKeyPathContentSize;
|
|
||||||
UIKIT_EXTERN NSString *const MJRefreshKeyPathContentInset;
|
|
||||||
UIKIT_EXTERN NSString *const MJRefreshKeyPathPanState;
|
|
||||||
|
|
||||||
UIKIT_EXTERN NSString *const MJRefreshHeaderLastUpdatedTimeKey;
|
|
||||||
|
|
||||||
UIKIT_EXTERN NSString *const MJRefreshHeaderIdleText;
|
|
||||||
UIKIT_EXTERN NSString *const MJRefreshHeaderPullingText;
|
|
||||||
UIKIT_EXTERN NSString *const MJRefreshHeaderRefreshingText;
|
|
||||||
|
|
||||||
UIKIT_EXTERN NSString *const MJRefreshTrailerIdleText;
|
|
||||||
UIKIT_EXTERN NSString *const MJRefreshTrailerPullingText;
|
|
||||||
|
|
||||||
UIKIT_EXTERN NSString *const MJRefreshAutoFooterIdleText;
|
|
||||||
UIKIT_EXTERN NSString *const MJRefreshAutoFooterRefreshingText;
|
|
||||||
UIKIT_EXTERN NSString *const MJRefreshAutoFooterNoMoreDataText;
|
|
||||||
|
|
||||||
UIKIT_EXTERN NSString *const MJRefreshBackFooterIdleText;
|
|
||||||
UIKIT_EXTERN NSString *const MJRefreshBackFooterPullingText;
|
|
||||||
UIKIT_EXTERN NSString *const MJRefreshBackFooterRefreshingText;
|
|
||||||
UIKIT_EXTERN NSString *const MJRefreshBackFooterNoMoreDataText;
|
|
||||||
|
|
||||||
UIKIT_EXTERN NSString *const MJRefreshHeaderLastTimeText;
|
|
||||||
UIKIT_EXTERN NSString *const MJRefreshHeaderDateTodayText;
|
|
||||||
UIKIT_EXTERN NSString *const MJRefreshHeaderNoneLastDateText;
|
|
||||||
|
|
||||||
UIKIT_EXTERN NSString *const MJRefreshDidChangeLanguageNotification;
|
|
||||||
|
|
||||||
// 状态检查
|
|
||||||
#define MJRefreshCheckState \
|
|
||||||
MJRefreshState oldState = self.state; \
|
|
||||||
if (state == oldState) return; \
|
|
||||||
[super setState:state];
|
|
||||||
|
|
||||||
// 异步主线程执行,不强持有Self
|
|
||||||
#define MJRefreshDispatchAsyncOnMainQueue(x) \
|
|
||||||
__weak typeof(self) weakSelf = self; \
|
|
||||||
dispatch_async(dispatch_get_main_queue(), ^{ \
|
|
||||||
typeof(weakSelf) self = weakSelf; \
|
|
||||||
{x} \
|
|
||||||
});
|
|
||||||
|
|
||||||
/// 替换方法实现
|
|
||||||
/// @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;
|
|
||||||
}
|
|
||||||
|
|
||||||
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 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 {
|
|
||||||
method_exchangeImplementations(oriMethod, newMethod);
|
|
||||||
}
|
|
||||||
return YES;
|
|
||||||
}
|
|
||||||
39
Pods/MJRefresh/MJRefresh/MJRefreshConst.m
generated
39
Pods/MJRefresh/MJRefresh/MJRefreshConst.m
generated
@ -1,39 +0,0 @@
|
|||||||
// 代码地址: https://github.com/CoderMJLee/MJRefresh
|
|
||||||
#import <UIKit/UIKit.h>
|
|
||||||
|
|
||||||
const CGFloat MJRefreshLabelLeftInset = 25;
|
|
||||||
const CGFloat MJRefreshHeaderHeight = 54.0;
|
|
||||||
const CGFloat MJRefreshFooterHeight = 44.0;
|
|
||||||
const CGFloat MJRefreshTrailWidth = 60.0;
|
|
||||||
const CGFloat MJRefreshFastAnimationDuration = 0.25;
|
|
||||||
const CGFloat MJRefreshSlowAnimationDuration = 0.4;
|
|
||||||
|
|
||||||
|
|
||||||
NSString *const MJRefreshKeyPathContentOffset = @"contentOffset";
|
|
||||||
NSString *const MJRefreshKeyPathContentInset = @"contentInset";
|
|
||||||
NSString *const MJRefreshKeyPathContentSize = @"contentSize";
|
|
||||||
NSString *const MJRefreshKeyPathPanState = @"state";
|
|
||||||
|
|
||||||
NSString *const MJRefreshHeaderLastUpdatedTimeKey = @"MJRefreshHeaderLastUpdatedTimeKey";
|
|
||||||
|
|
||||||
NSString *const MJRefreshHeaderIdleText = @"MJRefreshHeaderIdleText";
|
|
||||||
NSString *const MJRefreshHeaderPullingText = @"MJRefreshHeaderPullingText";
|
|
||||||
NSString *const MJRefreshHeaderRefreshingText = @"MJRefreshHeaderRefreshingText";
|
|
||||||
|
|
||||||
NSString *const MJRefreshTrailerIdleText = @"MJRefreshTrailerIdleText";
|
|
||||||
NSString *const MJRefreshTrailerPullingText = @"MJRefreshTrailerPullingText";
|
|
||||||
|
|
||||||
NSString *const MJRefreshAutoFooterIdleText = @"MJRefreshAutoFooterIdleText";
|
|
||||||
NSString *const MJRefreshAutoFooterRefreshingText = @"MJRefreshAutoFooterRefreshingText";
|
|
||||||
NSString *const MJRefreshAutoFooterNoMoreDataText = @"MJRefreshAutoFooterNoMoreDataText";
|
|
||||||
|
|
||||||
NSString *const MJRefreshBackFooterIdleText = @"MJRefreshBackFooterIdleText";
|
|
||||||
NSString *const MJRefreshBackFooterPullingText = @"MJRefreshBackFooterPullingText";
|
|
||||||
NSString *const MJRefreshBackFooterRefreshingText = @"MJRefreshBackFooterRefreshingText";
|
|
||||||
NSString *const MJRefreshBackFooterNoMoreDataText = @"MJRefreshBackFooterNoMoreDataText";
|
|
||||||
|
|
||||||
NSString *const MJRefreshHeaderLastTimeText = @"MJRefreshHeaderLastTimeText";
|
|
||||||
NSString *const MJRefreshHeaderDateTodayText = @"MJRefreshHeaderDateTodayText";
|
|
||||||
NSString *const MJRefreshHeaderNoneLastDateText = @"MJRefreshHeaderNoneLastDateText";
|
|
||||||
|
|
||||||
NSString *const MJRefreshDidChangeLanguageNotification = @"MJRefreshDidChangeLanguageNotification";
|
|
||||||
21
Pods/MJRefresh/MJRefresh/NSBundle+MJRefresh.h
generated
21
Pods/MJRefresh/MJRefresh/NSBundle+MJRefresh.h
generated
@ -1,21 +0,0 @@
|
|||||||
//
|
|
||||||
// NSBundle+MJRefresh.h
|
|
||||||
// MJRefresh
|
|
||||||
//
|
|
||||||
// Created by MJ Lee on 16/6/13.
|
|
||||||
// Copyright © 2016年 小码哥. All rights reserved.
|
|
||||||
//
|
|
||||||
|
|
||||||
#import <UIKit/UIKit.h>
|
|
||||||
|
|
||||||
NS_ASSUME_NONNULL_BEGIN
|
|
||||||
|
|
||||||
@interface NSBundle (MJRefresh)
|
|
||||||
+ (instancetype)mj_refreshBundle;
|
|
||||||
+ (UIImage *)mj_arrowImage;
|
|
||||||
+ (UIImage *)mj_trailArrowImage;
|
|
||||||
+ (NSString *)mj_localizedStringForKey:(NSString *)key value:(nullable NSString *)value;
|
|
||||||
+ (NSString *)mj_localizedStringForKey:(NSString *)key;
|
|
||||||
@end
|
|
||||||
|
|
||||||
NS_ASSUME_NONNULL_END
|
|
||||||
116
Pods/MJRefresh/MJRefresh/NSBundle+MJRefresh.m
generated
116
Pods/MJRefresh/MJRefresh/NSBundle+MJRefresh.m
generated
@ -1,116 +0,0 @@
|
|||||||
//
|
|
||||||
// NSBundle+MJRefresh.m
|
|
||||||
// MJRefresh
|
|
||||||
//
|
|
||||||
// Created by MJ Lee on 16/6/13.
|
|
||||||
// Copyright © 2016年 小码哥. All rights reserved.
|
|
||||||
//
|
|
||||||
|
|
||||||
#import "NSBundle+MJRefresh.h"
|
|
||||||
#import "MJRefreshComponent.h"
|
|
||||||
#import "MJRefreshConfig.h"
|
|
||||||
|
|
||||||
static NSBundle *mj_defaultI18nBundle = nil;
|
|
||||||
static NSBundle *mj_systemI18nBundle = nil;
|
|
||||||
|
|
||||||
@implementation NSBundle (MJRefresh)
|
|
||||||
+ (instancetype)mj_refreshBundle
|
|
||||||
{
|
|
||||||
static NSBundle *refreshBundle = nil;
|
|
||||||
if (refreshBundle == nil) {
|
|
||||||
#ifdef SWIFT_PACKAGE
|
|
||||||
NSBundle *containnerBundle = SWIFTPM_MODULE_BUNDLE;
|
|
||||||
#else
|
|
||||||
NSBundle *containnerBundle = [NSBundle bundleForClass:[MJRefreshComponent class]];
|
|
||||||
#endif
|
|
||||||
refreshBundle = [NSBundle bundleWithPath:[containnerBundle pathForResource:@"MJRefresh" ofType:@"bundle"]];
|
|
||||||
}
|
|
||||||
return refreshBundle;
|
|
||||||
}
|
|
||||||
|
|
||||||
+ (UIImage *)mj_arrowImage
|
|
||||||
{
|
|
||||||
static UIImage *arrowImage = nil;
|
|
||||||
if (arrowImage == nil) {
|
|
||||||
arrowImage = [[UIImage imageWithContentsOfFile:[[self mj_refreshBundle] pathForResource:@"arrow@2x" ofType:@"png"]] imageWithRenderingMode:UIImageRenderingModeAlwaysTemplate];
|
|
||||||
}
|
|
||||||
return arrowImage;
|
|
||||||
}
|
|
||||||
|
|
||||||
+ (UIImage *)mj_trailArrowImage {
|
|
||||||
static UIImage *arrowImage = nil;
|
|
||||||
if (arrowImage == nil) {
|
|
||||||
arrowImage = [[UIImage imageWithContentsOfFile:[[self mj_refreshBundle] pathForResource:@"trail_arrow@2x" ofType:@"png"]] imageWithRenderingMode:UIImageRenderingModeAlwaysTemplate];
|
|
||||||
}
|
|
||||||
return arrowImage;
|
|
||||||
}
|
|
||||||
|
|
||||||
+ (NSString *)mj_localizedStringForKey:(NSString *)key
|
|
||||||
{
|
|
||||||
return [self mj_localizedStringForKey:key value:nil];
|
|
||||||
}
|
|
||||||
|
|
||||||
+ (NSString *)mj_localizedStringForKey:(NSString *)key value:(NSString *)value
|
|
||||||
{
|
|
||||||
NSString *table = MJRefreshConfig.defaultConfig.i18nFilename;
|
|
||||||
|
|
||||||
// 如果没有缓存, 则走初始化逻辑
|
|
||||||
if (mj_defaultI18nBundle == nil) {
|
|
||||||
NSString *language = MJRefreshConfig.defaultConfig.languageCode;
|
|
||||||
// 如果配置中没有配置语言
|
|
||||||
if (!language) {
|
|
||||||
language = [NSLocale preferredLanguages].firstObject;
|
|
||||||
}
|
|
||||||
NSBundle *bundle = MJRefreshConfig.defaultConfig.i18nBundle;
|
|
||||||
// 首先优先使用公共配置中的 i18nBundle, 如果为空则使用 mainBundle
|
|
||||||
bundle = bundle ? bundle : NSBundle.mainBundle;
|
|
||||||
// 按语言选取语言包
|
|
||||||
NSString *i18nFolderPath = [bundle pathForResource:language ofType:@"lproj"];
|
|
||||||
mj_defaultI18nBundle = [NSBundle bundleWithPath:i18nFolderPath];
|
|
||||||
// 检查语言包, 如果没有查找到, 则默认使用 mainBundle
|
|
||||||
mj_defaultI18nBundle = mj_defaultI18nBundle ? mj_defaultI18nBundle : NSBundle.mainBundle;
|
|
||||||
|
|
||||||
// 获取 MJRefresh 自有的语言包
|
|
||||||
if (mj_systemI18nBundle == nil) {
|
|
||||||
mj_systemI18nBundle = [self mj_defaultI18nBundleWithLanguage:language];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// 首先在 MJRefresh 内置语言文件中寻找
|
|
||||||
value = [mj_systemI18nBundle localizedStringForKey:key value:value table:nil];
|
|
||||||
// 然后在 MainBundle 对应语言文件中寻找
|
|
||||||
value = [mj_defaultI18nBundle localizedStringForKey:key value:value table:table];
|
|
||||||
return value;
|
|
||||||
}
|
|
||||||
|
|
||||||
+ (NSBundle *)mj_defaultI18nBundleWithLanguage:(NSString *)language {
|
|
||||||
if ([language hasPrefix:@"en"]) {
|
|
||||||
language = @"en";
|
|
||||||
} else if ([language hasPrefix:@"zh"]) {
|
|
||||||
if ([language rangeOfString:@"Hans"].location != NSNotFound) {
|
|
||||||
language = @"zh-Hans"; // 简体中文
|
|
||||||
} else { // zh-Hant\zh-HK\zh-TW
|
|
||||||
language = @"zh-Hant"; // 繁體中文
|
|
||||||
}
|
|
||||||
} else if ([language hasPrefix:@"ko"]) {
|
|
||||||
language = @"ko";
|
|
||||||
} else if ([language hasPrefix:@"ru"]) {
|
|
||||||
language = @"ru";
|
|
||||||
} else if ([language hasPrefix:@"uk"]) {
|
|
||||||
language = @"uk";
|
|
||||||
} else {
|
|
||||||
language = @"en";
|
|
||||||
}
|
|
||||||
|
|
||||||
// 从MJRefresh.bundle中查找资源
|
|
||||||
return [NSBundle bundleWithPath:[[NSBundle mj_refreshBundle] pathForResource:language ofType:@"lproj"]];
|
|
||||||
}
|
|
||||||
@end
|
|
||||||
|
|
||||||
@implementation MJRefreshConfig (Bundle)
|
|
||||||
|
|
||||||
+ (void)resetLanguageResourceCache {
|
|
||||||
mj_defaultI18nBundle = nil;
|
|
||||||
mj_systemI18nBundle = nil;
|
|
||||||
}
|
|
||||||
|
|
||||||
@end
|
|
||||||
23
Pods/MJRefresh/MJRefresh/PrivacyInfo.xcprivacy
generated
23
Pods/MJRefresh/MJRefresh/PrivacyInfo.xcprivacy
generated
@ -1,23 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
|
||||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
|
||||||
<plist version="1.0">
|
|
||||||
<dict>
|
|
||||||
<key>NSPrivacyTracking</key>
|
|
||||||
<false/>
|
|
||||||
<key>NSPrivacyTrackingDomains</key>
|
|
||||||
<array/>
|
|
||||||
<key>NSPrivacyAccessedAPITypes</key>
|
|
||||||
<array>
|
|
||||||
<dict>
|
|
||||||
<key>NSPrivacyAccessedAPIType</key>
|
|
||||||
<string>NSPrivacyAccessedAPICategoryUserDefaults</string>
|
|
||||||
<key>NSPrivacyAccessedAPITypeReasons</key>
|
|
||||||
<array>
|
|
||||||
<string>CA92.1</string>
|
|
||||||
</array>
|
|
||||||
</dict>
|
|
||||||
</array>
|
|
||||||
<key>NSPrivacyCollectedDataTypes</key>
|
|
||||||
<array/>
|
|
||||||
</dict>
|
|
||||||
</plist>
|
|
||||||
@ -1,20 +0,0 @@
|
|||||||
//
|
|
||||||
// UICollectionViewLayout+MJRefresh.h
|
|
||||||
//
|
|
||||||
// 该类是用来解决 Footer 在底端加载完成后, 仍停留在原处的 bug.
|
|
||||||
// 此问题出现在 iOS 14 及以下系统上.
|
|
||||||
// Reference: https://github.com/CoderMJLee/MJRefresh/issues/1552
|
|
||||||
//
|
|
||||||
// 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
|
|
||||||
@ -1,45 +0,0 @@
|
|||||||
//
|
|
||||||
// UICollectionViewLayout+MJRefresh.m
|
|
||||||
//
|
|
||||||
// 该类是用来解决 Footer 在底端加载完成后, 仍停留在原处的 bug.
|
|
||||||
// 此问题出现在 iOS 14 及以下系统上.
|
|
||||||
// Reference: https://github.com/CoderMJLee/MJRefresh/issues/1552
|
|
||||||
//
|
|
||||||
// Created by jiasong on 2021/11/15.
|
|
||||||
// Copyright © 2021 小码哥. All rights reserved.
|
|
||||||
//
|
|
||||||
|
|
||||||
#import "UICollectionViewLayout+MJRefresh.h"
|
|
||||||
#import "MJRefreshConst.h"
|
|
||||||
#import "MJRefreshFooter.h"
|
|
||||||
#import "UIScrollView+MJRefresh.h"
|
|
||||||
|
|
||||||
@implementation UICollectionViewLayout (MJRefresh)
|
|
||||||
|
|
||||||
+ (void)load {
|
|
||||||
static dispatch_once_t onceToken;
|
|
||||||
dispatch_once(&onceToken, ^{
|
|
||||||
MJRefreshExchangeImplementations(self.class, @selector(finalizeCollectionViewUpdates),
|
|
||||||
self.class, @selector(mj_finalizeCollectionViewUpdates));
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
- (void)mj_finalizeCollectionViewUpdates {
|
|
||||||
[self mj_finalizeCollectionViewUpdates];
|
|
||||||
|
|
||||||
__kindof MJRefreshFooter *footer = self.collectionView.mj_footer;
|
|
||||||
CGSize newSize = self.collectionViewContentSize;
|
|
||||||
CGSize oldSize = self.collectionView.contentSize;
|
|
||||||
if (footer != nil && !CGSizeEqualToSize(newSize, oldSize)) {
|
|
||||||
NSDictionary *changed = @{
|
|
||||||
NSKeyValueChangeNewKey: [NSValue valueWithCGSize:newSize],
|
|
||||||
NSKeyValueChangeOldKey: [NSValue valueWithCGSize:oldSize],
|
|
||||||
};
|
|
||||||
[CATransaction begin];
|
|
||||||
[CATransaction setDisableActions:YES];
|
|
||||||
[footer scrollViewContentSizeDidChange:changed];
|
|
||||||
[CATransaction commit];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@end
|
|
||||||
28
Pods/MJRefresh/MJRefresh/UIScrollView+MJExtension.h
generated
28
Pods/MJRefresh/MJRefresh/UIScrollView+MJExtension.h
generated
@ -1,28 +0,0 @@
|
|||||||
// 代码地址: https://github.com/CoderMJLee/MJRefresh
|
|
||||||
// UIScrollView+Extension.h
|
|
||||||
// MJRefresh
|
|
||||||
//
|
|
||||||
// Created by MJ Lee on 14-5-28.
|
|
||||||
// Copyright (c) 2014年 小码哥. All rights reserved.
|
|
||||||
//
|
|
||||||
|
|
||||||
#import <UIKit/UIKit.h>
|
|
||||||
|
|
||||||
NS_ASSUME_NONNULL_BEGIN
|
|
||||||
|
|
||||||
@interface UIScrollView (MJExtension)
|
|
||||||
@property (readonly, nonatomic) UIEdgeInsets mj_inset;
|
|
||||||
|
|
||||||
@property (assign, nonatomic) CGFloat mj_insetT;
|
|
||||||
@property (assign, nonatomic) CGFloat mj_insetB;
|
|
||||||
@property (assign, nonatomic) CGFloat mj_insetL;
|
|
||||||
@property (assign, nonatomic) CGFloat mj_insetR;
|
|
||||||
|
|
||||||
@property (assign, nonatomic) CGFloat mj_offsetX;
|
|
||||||
@property (assign, nonatomic) CGFloat mj_offsetY;
|
|
||||||
|
|
||||||
@property (assign, nonatomic) CGFloat mj_contentW;
|
|
||||||
@property (assign, nonatomic) CGFloat mj_contentH;
|
|
||||||
@end
|
|
||||||
|
|
||||||
NS_ASSUME_NONNULL_END
|
|
||||||
153
Pods/MJRefresh/MJRefresh/UIScrollView+MJExtension.m
generated
153
Pods/MJRefresh/MJRefresh/UIScrollView+MJExtension.m
generated
@ -1,153 +0,0 @@
|
|||||||
// 代码地址: https://github.com/CoderMJLee/MJRefresh
|
|
||||||
// UIScrollView+Extension.m
|
|
||||||
// MJRefresh
|
|
||||||
//
|
|
||||||
// Created by MJ Lee on 14-5-28.
|
|
||||||
// Copyright (c) 2014年 小码哥. All rights reserved.
|
|
||||||
//
|
|
||||||
|
|
||||||
#import "UIScrollView+MJExtension.h"
|
|
||||||
#import <objc/runtime.h>
|
|
||||||
|
|
||||||
#pragma clang diagnostic push
|
|
||||||
#pragma clang diagnostic ignored "-Wunguarded-availability-new"
|
|
||||||
|
|
||||||
@implementation UIScrollView (MJExtension)
|
|
||||||
|
|
||||||
static BOOL respondsToAdjustedContentInset_;
|
|
||||||
|
|
||||||
+ (void)load
|
|
||||||
{
|
|
||||||
static dispatch_once_t onceToken;
|
|
||||||
dispatch_once(&onceToken, ^{
|
|
||||||
respondsToAdjustedContentInset_ = [self instancesRespondToSelector:@selector(adjustedContentInset)];
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
- (UIEdgeInsets)mj_inset
|
|
||||||
{
|
|
||||||
#ifdef __IPHONE_11_0
|
|
||||||
if (respondsToAdjustedContentInset_) {
|
|
||||||
return self.adjustedContentInset;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
return self.contentInset;
|
|
||||||
}
|
|
||||||
|
|
||||||
- (void)setMj_insetT:(CGFloat)mj_insetT
|
|
||||||
{
|
|
||||||
UIEdgeInsets inset = self.contentInset;
|
|
||||||
inset.top = mj_insetT;
|
|
||||||
#ifdef __IPHONE_11_0
|
|
||||||
if (respondsToAdjustedContentInset_) {
|
|
||||||
inset.top -= (self.adjustedContentInset.top - self.contentInset.top);
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
self.contentInset = inset;
|
|
||||||
}
|
|
||||||
|
|
||||||
- (CGFloat)mj_insetT
|
|
||||||
{
|
|
||||||
return self.mj_inset.top;
|
|
||||||
}
|
|
||||||
|
|
||||||
- (void)setMj_insetB:(CGFloat)mj_insetB
|
|
||||||
{
|
|
||||||
UIEdgeInsets inset = self.contentInset;
|
|
||||||
inset.bottom = mj_insetB;
|
|
||||||
#ifdef __IPHONE_11_0
|
|
||||||
if (respondsToAdjustedContentInset_) {
|
|
||||||
inset.bottom -= (self.adjustedContentInset.bottom - self.contentInset.bottom);
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
self.contentInset = inset;
|
|
||||||
}
|
|
||||||
|
|
||||||
- (CGFloat)mj_insetB
|
|
||||||
{
|
|
||||||
return self.mj_inset.bottom;
|
|
||||||
}
|
|
||||||
|
|
||||||
- (void)setMj_insetL:(CGFloat)mj_insetL
|
|
||||||
{
|
|
||||||
UIEdgeInsets inset = self.contentInset;
|
|
||||||
inset.left = mj_insetL;
|
|
||||||
#ifdef __IPHONE_11_0
|
|
||||||
if (respondsToAdjustedContentInset_) {
|
|
||||||
inset.left -= (self.adjustedContentInset.left - self.contentInset.left);
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
self.contentInset = inset;
|
|
||||||
}
|
|
||||||
|
|
||||||
- (CGFloat)mj_insetL
|
|
||||||
{
|
|
||||||
return self.mj_inset.left;
|
|
||||||
}
|
|
||||||
|
|
||||||
- (void)setMj_insetR:(CGFloat)mj_insetR
|
|
||||||
{
|
|
||||||
UIEdgeInsets inset = self.contentInset;
|
|
||||||
inset.right = mj_insetR;
|
|
||||||
#ifdef __IPHONE_11_0
|
|
||||||
if (respondsToAdjustedContentInset_) {
|
|
||||||
inset.right -= (self.adjustedContentInset.right - self.contentInset.right);
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
self.contentInset = inset;
|
|
||||||
}
|
|
||||||
|
|
||||||
- (CGFloat)mj_insetR
|
|
||||||
{
|
|
||||||
return self.mj_inset.right;
|
|
||||||
}
|
|
||||||
|
|
||||||
- (void)setMj_offsetX:(CGFloat)mj_offsetX
|
|
||||||
{
|
|
||||||
CGPoint offset = self.contentOffset;
|
|
||||||
offset.x = mj_offsetX;
|
|
||||||
self.contentOffset = offset;
|
|
||||||
}
|
|
||||||
|
|
||||||
- (CGFloat)mj_offsetX
|
|
||||||
{
|
|
||||||
return self.contentOffset.x;
|
|
||||||
}
|
|
||||||
|
|
||||||
- (void)setMj_offsetY:(CGFloat)mj_offsetY
|
|
||||||
{
|
|
||||||
CGPoint offset = self.contentOffset;
|
|
||||||
offset.y = mj_offsetY;
|
|
||||||
self.contentOffset = offset;
|
|
||||||
}
|
|
||||||
|
|
||||||
- (CGFloat)mj_offsetY
|
|
||||||
{
|
|
||||||
return self.contentOffset.y;
|
|
||||||
}
|
|
||||||
|
|
||||||
- (void)setMj_contentW:(CGFloat)mj_contentW
|
|
||||||
{
|
|
||||||
CGSize size = self.contentSize;
|
|
||||||
size.width = mj_contentW;
|
|
||||||
self.contentSize = size;
|
|
||||||
}
|
|
||||||
|
|
||||||
- (CGFloat)mj_contentW
|
|
||||||
{
|
|
||||||
return self.contentSize.width;
|
|
||||||
}
|
|
||||||
|
|
||||||
- (void)setMj_contentH:(CGFloat)mj_contentH
|
|
||||||
{
|
|
||||||
CGSize size = self.contentSize;
|
|
||||||
size.height = mj_contentH;
|
|
||||||
self.contentSize = size;
|
|
||||||
}
|
|
||||||
|
|
||||||
- (CGFloat)mj_contentH
|
|
||||||
{
|
|
||||||
return self.contentSize.height;
|
|
||||||
}
|
|
||||||
@end
|
|
||||||
#pragma clang diagnostic pop
|
|
||||||
36
Pods/MJRefresh/MJRefresh/UIScrollView+MJRefresh.h
generated
36
Pods/MJRefresh/MJRefresh/UIScrollView+MJRefresh.h
generated
@ -1,36 +0,0 @@
|
|||||||
// 代码地址: https://github.com/CoderMJLee/MJRefresh
|
|
||||||
// UIScrollView+MJRefresh.h
|
|
||||||
// MJRefresh
|
|
||||||
//
|
|
||||||
// Created by MJ Lee on 15/3/4.
|
|
||||||
// Copyright (c) 2015年 小码哥. All rights reserved.
|
|
||||||
// 给ScrollView增加下拉刷新、上拉刷新、 左滑刷新的功能
|
|
||||||
|
|
||||||
#import <UIKit/UIKit.h>
|
|
||||||
#if __has_include(<MJRefresh/MJRefreshConst.h>)
|
|
||||||
#import <MJRefresh/MJRefreshConst.h>
|
|
||||||
#else
|
|
||||||
#import "MJRefreshConst.h"
|
|
||||||
#endif
|
|
||||||
|
|
||||||
@class MJRefreshHeader, MJRefreshFooter, MJRefreshTrailer;
|
|
||||||
|
|
||||||
NS_ASSUME_NONNULL_BEGIN
|
|
||||||
|
|
||||||
@interface UIScrollView (MJRefresh)
|
|
||||||
/** 下拉刷新控件 */
|
|
||||||
@property (strong, nonatomic, nullable) MJRefreshHeader *mj_header;
|
|
||||||
@property (strong, nonatomic, nullable) MJRefreshHeader *header MJRefreshDeprecated("使用mj_header");
|
|
||||||
/** 上拉刷新控件 */
|
|
||||||
@property (strong, nonatomic, nullable) MJRefreshFooter *mj_footer;
|
|
||||||
@property (strong, nonatomic, nullable) MJRefreshFooter *footer MJRefreshDeprecated("使用mj_footer");
|
|
||||||
|
|
||||||
/** 左滑刷新控件 */
|
|
||||||
@property (strong, nonatomic, nullable) MJRefreshTrailer *mj_trailer;
|
|
||||||
|
|
||||||
#pragma mark - other
|
|
||||||
- (NSInteger)mj_totalDataCount;
|
|
||||||
|
|
||||||
@end
|
|
||||||
|
|
||||||
NS_ASSUME_NONNULL_END
|
|
||||||
120
Pods/MJRefresh/MJRefresh/UIScrollView+MJRefresh.m
generated
120
Pods/MJRefresh/MJRefresh/UIScrollView+MJRefresh.m
generated
@ -1,120 +0,0 @@
|
|||||||
// 代码地址: https://github.com/CoderMJLee/MJRefresh
|
|
||||||
// UIScrollView+MJRefresh.m
|
|
||||||
// MJRefresh
|
|
||||||
//
|
|
||||||
// Created by MJ Lee on 15/3/4.
|
|
||||||
// Copyright (c) 2015年 小码哥. All rights reserved.
|
|
||||||
//
|
|
||||||
|
|
||||||
#import "UIScrollView+MJRefresh.h"
|
|
||||||
#import "MJRefreshHeader.h"
|
|
||||||
#import "MJRefreshFooter.h"
|
|
||||||
#import "MJRefreshTrailer.h"
|
|
||||||
#import <objc/runtime.h>
|
|
||||||
|
|
||||||
@implementation UIScrollView (MJRefresh)
|
|
||||||
|
|
||||||
#pragma mark - header
|
|
||||||
static const char MJRefreshHeaderKey = '\0';
|
|
||||||
- (void)setMj_header:(MJRefreshHeader *)mj_header
|
|
||||||
{
|
|
||||||
if (mj_header != self.mj_header) {
|
|
||||||
// 删除旧的,添加新的
|
|
||||||
[self.mj_header removeFromSuperview];
|
|
||||||
|
|
||||||
if (mj_header) {
|
|
||||||
[self insertSubview:mj_header atIndex:0];
|
|
||||||
}
|
|
||||||
// 存储新的
|
|
||||||
objc_setAssociatedObject(self, &MJRefreshHeaderKey,
|
|
||||||
mj_header, OBJC_ASSOCIATION_RETAIN);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
- (MJRefreshHeader *)mj_header
|
|
||||||
{
|
|
||||||
return objc_getAssociatedObject(self, &MJRefreshHeaderKey);
|
|
||||||
}
|
|
||||||
|
|
||||||
#pragma mark - footer
|
|
||||||
static const char MJRefreshFooterKey = '\0';
|
|
||||||
- (void)setMj_footer:(MJRefreshFooter *)mj_footer
|
|
||||||
{
|
|
||||||
if (mj_footer != self.mj_footer) {
|
|
||||||
// 删除旧的,添加新的
|
|
||||||
[self.mj_footer removeFromSuperview];
|
|
||||||
if (mj_footer) {
|
|
||||||
[self insertSubview:mj_footer atIndex:0];
|
|
||||||
}
|
|
||||||
// 存储新的
|
|
||||||
objc_setAssociatedObject(self, &MJRefreshFooterKey,
|
|
||||||
mj_footer, OBJC_ASSOCIATION_RETAIN);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
- (MJRefreshFooter *)mj_footer
|
|
||||||
{
|
|
||||||
return objc_getAssociatedObject(self, &MJRefreshFooterKey);
|
|
||||||
}
|
|
||||||
|
|
||||||
#pragma mark - footer
|
|
||||||
static const char MJRefreshTrailerKey = '\0';
|
|
||||||
- (void)setMj_trailer:(MJRefreshTrailer *)mj_trailer {
|
|
||||||
if (mj_trailer != self.mj_trailer) {
|
|
||||||
// 删除旧的,添加新的
|
|
||||||
[self.mj_trailer removeFromSuperview];
|
|
||||||
if (mj_trailer) {
|
|
||||||
[self insertSubview:mj_trailer atIndex:0];
|
|
||||||
}
|
|
||||||
// 存储新的
|
|
||||||
objc_setAssociatedObject(self, &MJRefreshTrailerKey,
|
|
||||||
mj_trailer, OBJC_ASSOCIATION_RETAIN);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
- (MJRefreshTrailer *)mj_trailer {
|
|
||||||
return objc_getAssociatedObject(self, &MJRefreshTrailerKey);
|
|
||||||
}
|
|
||||||
|
|
||||||
#pragma mark - 过期
|
|
||||||
- (void)setFooter:(MJRefreshFooter *)footer
|
|
||||||
{
|
|
||||||
self.mj_footer = footer;
|
|
||||||
}
|
|
||||||
|
|
||||||
- (MJRefreshFooter *)footer
|
|
||||||
{
|
|
||||||
return self.mj_footer;
|
|
||||||
}
|
|
||||||
|
|
||||||
- (void)setHeader:(MJRefreshHeader *)header
|
|
||||||
{
|
|
||||||
self.mj_header = header;
|
|
||||||
}
|
|
||||||
|
|
||||||
- (MJRefreshHeader *)header
|
|
||||||
{
|
|
||||||
return self.mj_header;
|
|
||||||
}
|
|
||||||
|
|
||||||
#pragma mark - other
|
|
||||||
- (NSInteger)mj_totalDataCount
|
|
||||||
{
|
|
||||||
NSInteger totalCount = 0;
|
|
||||||
if ([self isKindOfClass:[UITableView class]]) {
|
|
||||||
UITableView *tableView = (UITableView *)self;
|
|
||||||
|
|
||||||
for (NSInteger section = 0; section < tableView.numberOfSections; section++) {
|
|
||||||
totalCount += [tableView numberOfRowsInSection:section];
|
|
||||||
}
|
|
||||||
} else if ([self isKindOfClass:[UICollectionView class]]) {
|
|
||||||
UICollectionView *collectionView = (UICollectionView *)self;
|
|
||||||
|
|
||||||
for (NSInteger section = 0; section < collectionView.numberOfSections; section++) {
|
|
||||||
totalCount += [collectionView numberOfItemsInSection:section];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return totalCount;
|
|
||||||
}
|
|
||||||
|
|
||||||
@end
|
|
||||||
22
Pods/MJRefresh/MJRefresh/UIView+MJExtension.h
generated
22
Pods/MJRefresh/MJRefresh/UIView+MJExtension.h
generated
@ -1,22 +0,0 @@
|
|||||||
// 代码地址: https://github.com/CoderMJLee/MJRefresh
|
|
||||||
// UIView+Extension.h
|
|
||||||
// MJRefresh
|
|
||||||
//
|
|
||||||
// Created by MJ Lee on 14-5-28.
|
|
||||||
// Copyright (c) 2014年 小码哥. All rights reserved.
|
|
||||||
//
|
|
||||||
|
|
||||||
#import <UIKit/UIKit.h>
|
|
||||||
|
|
||||||
NS_ASSUME_NONNULL_BEGIN
|
|
||||||
|
|
||||||
@interface UIView (MJExtension)
|
|
||||||
@property (assign, nonatomic) CGFloat mj_x;
|
|
||||||
@property (assign, nonatomic) CGFloat mj_y;
|
|
||||||
@property (assign, nonatomic) CGFloat mj_w;
|
|
||||||
@property (assign, nonatomic) CGFloat mj_h;
|
|
||||||
@property (assign, nonatomic) CGSize mj_size;
|
|
||||||
@property (assign, nonatomic) CGPoint mj_origin;
|
|
||||||
@end
|
|
||||||
|
|
||||||
NS_ASSUME_NONNULL_END
|
|
||||||
83
Pods/MJRefresh/MJRefresh/UIView+MJExtension.m
generated
83
Pods/MJRefresh/MJRefresh/UIView+MJExtension.m
generated
@ -1,83 +0,0 @@
|
|||||||
// 代码地址: https://github.com/CoderMJLee/MJRefresh
|
|
||||||
// UIView+Extension.m
|
|
||||||
// MJRefresh
|
|
||||||
//
|
|
||||||
// Created by MJ Lee on 14-5-28.
|
|
||||||
// Copyright (c) 2014年 小码哥. All rights reserved.
|
|
||||||
//
|
|
||||||
|
|
||||||
#import "UIView+MJExtension.h"
|
|
||||||
|
|
||||||
@implementation UIView (MJExtension)
|
|
||||||
- (void)setMj_x:(CGFloat)mj_x
|
|
||||||
{
|
|
||||||
CGRect frame = self.frame;
|
|
||||||
frame.origin.x = mj_x;
|
|
||||||
self.frame = frame;
|
|
||||||
}
|
|
||||||
|
|
||||||
- (CGFloat)mj_x
|
|
||||||
{
|
|
||||||
return self.frame.origin.x;
|
|
||||||
}
|
|
||||||
|
|
||||||
- (void)setMj_y:(CGFloat)mj_y
|
|
||||||
{
|
|
||||||
CGRect frame = self.frame;
|
|
||||||
frame.origin.y = mj_y;
|
|
||||||
self.frame = frame;
|
|
||||||
}
|
|
||||||
|
|
||||||
- (CGFloat)mj_y
|
|
||||||
{
|
|
||||||
return self.frame.origin.y;
|
|
||||||
}
|
|
||||||
|
|
||||||
- (void)setMj_w:(CGFloat)mj_w
|
|
||||||
{
|
|
||||||
CGRect frame = self.frame;
|
|
||||||
frame.size.width = mj_w;
|
|
||||||
self.frame = frame;
|
|
||||||
}
|
|
||||||
|
|
||||||
- (CGFloat)mj_w
|
|
||||||
{
|
|
||||||
return self.frame.size.width;
|
|
||||||
}
|
|
||||||
|
|
||||||
- (void)setMj_h:(CGFloat)mj_h
|
|
||||||
{
|
|
||||||
CGRect frame = self.frame;
|
|
||||||
frame.size.height = mj_h;
|
|
||||||
self.frame = frame;
|
|
||||||
}
|
|
||||||
|
|
||||||
- (CGFloat)mj_h
|
|
||||||
{
|
|
||||||
return self.frame.size.height;
|
|
||||||
}
|
|
||||||
|
|
||||||
- (void)setMj_size:(CGSize)mj_size
|
|
||||||
{
|
|
||||||
CGRect frame = self.frame;
|
|
||||||
frame.size = mj_size;
|
|
||||||
self.frame = frame;
|
|
||||||
}
|
|
||||||
|
|
||||||
- (CGSize)mj_size
|
|
||||||
{
|
|
||||||
return self.frame.size;
|
|
||||||
}
|
|
||||||
|
|
||||||
- (void)setMj_origin:(CGPoint)mj_origin
|
|
||||||
{
|
|
||||||
CGRect frame = self.frame;
|
|
||||||
frame.origin = mj_origin;
|
|
||||||
self.frame = frame;
|
|
||||||
}
|
|
||||||
|
|
||||||
- (CGPoint)mj_origin
|
|
||||||
{
|
|
||||||
return self.frame.origin;
|
|
||||||
}
|
|
||||||
@end
|
|
||||||
457
Pods/MJRefresh/README.md
generated
457
Pods/MJRefresh/README.md
generated
@ -1,457 +0,0 @@
|
|||||||
## MJRefresh
|
|
||||||
[](https://github.com/apple/swift-package-manager)
|
|
||||||
[](https://github.com/Carthage/Carthage)
|
|
||||||
[](https://cocoapods.org/pods/MJRefresh)
|
|
||||||
|
|
||||||
* An easy way to use pull-to-refresh
|
|
||||||
|
|
||||||
[📜✍🏻**Release Notes**: more details](https://github.com/CoderMJLee/MJRefresh/releases)
|
|
||||||
|
|
||||||
## Contents
|
|
||||||
|
|
||||||
- New Features
|
|
||||||
- [Dynamic i18n Switching](#dynamic_i18n_switching)
|
|
||||||
- [SPM Supported](#spm_supported)
|
|
||||||
- [Swift Chaining Grammar Supported](#swift_chaining_grammar_supported)
|
|
||||||
|
|
||||||
* Getting Started
|
|
||||||
* [Features【Support what kinds of controls to refresh】](#Support_what_kinds_of_controls_to_refresh)
|
|
||||||
* [Installation【How to use MJRefresh】](#How_to_use_MJRefresh)
|
|
||||||
* [Who's using【More than hundreds of Apps are using MJRefresh】](#More_than_hundreds_of_Apps_are_using_MJRefresh)
|
|
||||||
* [Classes【The Class Structure Chart of MJRefresh】](#The_Class_Structure_Chart_of_MJRefresh)
|
|
||||||
* Comment API
|
|
||||||
* [MJRefreshComponent.h](#MJRefreshComponent.h)
|
|
||||||
* [MJRefreshHeader.h](#MJRefreshHeader.h)
|
|
||||||
* [MJRefreshFooter.h](#MJRefreshFooter.h)
|
|
||||||
* [MJRefreshAutoFooter.h](#MJRefreshAutoFooter.h)
|
|
||||||
* [MJRefreshTrailer.h](#MJRefreshTrailer.h)
|
|
||||||
* Examples
|
|
||||||
* [Reference](#Reference)
|
|
||||||
* [The drop-down refresh 01-Default](#The_drop-down_refresh_01-Default)
|
|
||||||
* [The drop-down refresh 02-Animation image](#The_drop-down_refresh_02-Animation_image)
|
|
||||||
* [The drop-down refresh 03-Hide the time](#The_drop-down_refresh_03-Hide_the_time)
|
|
||||||
* [The drop-down refresh 04-Hide status and time](#The_drop-down_refresh_04-Hide_status_and_time)
|
|
||||||
* [The drop-down refresh 05-DIY title](#The_drop-down_refresh_05-DIY_title)
|
|
||||||
* [The drop-down refresh 06-DIY the control of refresh](#The_drop-down_refresh_06-DIY_the_control_of_refresh)
|
|
||||||
* [The pull to refresh 01-Default](#The_pull_to_refresh_01-Default)
|
|
||||||
* [The pull to refresh 02-Animation image](#The_pull_to_refresh_02-Animation_image)
|
|
||||||
* [The pull to refresh 03-Hide the title of refresh status](#The_pull_to_refresh_03-Hide_the_title_of_refresh_status)
|
|
||||||
* [The pull to refresh 04-All loaded](#The_pull_to_refresh_04-All_loaded)
|
|
||||||
* [The pull to refresh 05-DIY title](#The_pull_to_refresh_05-DIY_title)
|
|
||||||
* [The pull to refresh 06-Hidden After loaded](#The_pull_to_refresh_06-Hidden_After_loaded)
|
|
||||||
* [The pull to refresh 07-Automatic back of the pull01](#The_pull_to_refresh_07-Automatic_back_of_the_pull01)
|
|
||||||
* [The pull to refresh 08-Automatic back of the pull02](#The_pull_to_refresh_08-Automatic_back_of_the_pull02)
|
|
||||||
* [The pull to refresh 09-DIY the control of refresh(Automatic refresh)](#The_pull_to_refresh_09-DIY_the_control_of_refresh(Automatic_refresh))
|
|
||||||
* [The pull to refresh 10-DIY the control of refresh(Automatic back)](#The_pull_to_refresh_10-DIY_the_control_of_refresh(Automatic_back))
|
|
||||||
* [UICollectionView01-The pull and drop-down refresh](#UICollectionView01-The_pull_and_drop-down_refresh)
|
|
||||||
* [UICollectionView02-The trailer refresh](#UICollectionView02-The_trailer_refresh)
|
|
||||||
* [WKWebView01-The drop-down refresh](#WKWebView01-The_drop-down_refresh)
|
|
||||||
* [Hope](#Hope)
|
|
||||||
|
|
||||||
## New Features
|
|
||||||
### <a id="dynamic_i18n_switching"></a>Dynamic i18n Switching
|
|
||||||
|
|
||||||
Now `MJRefresh components` will be rerendered automatically with `MJRefreshConfig.default.language` setting.
|
|
||||||
|
|
||||||
#### Example
|
|
||||||
|
|
||||||
Go `i18n` folder and see lots of cases. Simulator example is behind `i18n tab` in right-top corner.
|
|
||||||
|
|
||||||
#### Setting language
|
|
||||||
|
|
||||||
```swift
|
|
||||||
MJRefreshConfig.default.language = "zh-hans"
|
|
||||||
```
|
|
||||||
|
|
||||||
#### Setting i18n file name
|
|
||||||
|
|
||||||
```swift
|
|
||||||
MJRefreshConfig.default.i18nFilename = "i18n File Name(not include type<.strings>)"
|
|
||||||
```
|
|
||||||
|
|
||||||
#### Setting i18n language bundle
|
|
||||||
|
|
||||||
```swift
|
|
||||||
MJRefreshConfig.default.i18nBundle = <i18n Bundle>
|
|
||||||
```
|
|
||||||
|
|
||||||
#### Adopting the feature in your DIY component
|
|
||||||
|
|
||||||
1. Just override `i18nDidChange` function and reset texts.
|
|
||||||
|
|
||||||
```swift
|
|
||||||
// must use this localization methods
|
|
||||||
Bundle.mj_localizedString(forKey: "")
|
|
||||||
// or
|
|
||||||
Bundle.mj_localizedString(forKey: "", value:"")
|
|
||||||
|
|
||||||
override func i18nDidChange() {
|
|
||||||
// Reset texts function
|
|
||||||
setupTexts()
|
|
||||||
// Make sure to call super after resetting texts. It will call placeSubViews for applying new layout.
|
|
||||||
super.i18nDidChange()
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
2. Receiving `MJRefreshDidChangeLanguageNotification` notification.
|
|
||||||
|
|
||||||
### <a id="spm_supported"></a>SPM Supported
|
|
||||||
|
|
||||||
Released from [`3.7.1`](https://github.com/CoderMJLee/MJRefresh/releases/tag/3.7.1)
|
|
||||||
|
|
||||||
### <a id="swift_chaining_grammar_supported"></a>Swift Chaining Grammar Supported
|
|
||||||
|
|
||||||
```swift
|
|
||||||
// Example as MJRefreshNormalHeader
|
|
||||||
func addRefreshHeader() {
|
|
||||||
MJRefreshNormalHeader { [weak self] in
|
|
||||||
// load some data
|
|
||||||
}.autoChangeTransparency(true)
|
|
||||||
.link(to: tableView)
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
## <a id="Support_what_kinds_of_controls_to_refresh"></a>Support what kinds of controls to refresh
|
|
||||||
|
|
||||||
* `UIScrollView`、`UITableView`、`UICollectionView`、`WKWebView`
|
|
||||||
|
|
||||||
## <a id="How_to_use_MJRefresh"></a>How to use MJRefresh
|
|
||||||
* Installation with CocoaPods:`pod 'MJRefresh'`
|
|
||||||
* Installation with [Carthage](https://github.com/Carthage/Carthage):`github "CoderMJLee/MJRefresh"`
|
|
||||||
* Manual import:
|
|
||||||
* Drag All files in the `MJRefresh` folder to project
|
|
||||||
* Import the main file:`#import "MJRefresh.h"`
|
|
||||||
|
|
||||||
```objc
|
|
||||||
Base Custom
|
|
||||||
MJRefresh.bundle MJRefresh.h
|
|
||||||
MJRefreshConst.h MJRefreshConst.m
|
|
||||||
UIScrollView+MJExtension.h UIScrollView+MJExtension.m
|
|
||||||
UIScrollView+MJRefresh.h UIScrollView+MJRefresh.m
|
|
||||||
UIView+MJExtension.h UIView+MJExtension.m
|
|
||||||
```
|
|
||||||
|
|
||||||
## <a id="More_than_hundreds_of_Apps_are_using_MJRefresh"></a>More than hundreds of Apps are using MJRefresh
|
|
||||||
<img src="http://images0.cnblogs.com/blog2015/497279/201506/141212365041650.png" width="200" height="300">
|
|
||||||
* More information of App can focus on:[M了个J-博客园](http://www.cnblogs.com/mjios/p/4409853.html)
|
|
||||||
|
|
||||||
## <a id="The_Class_Structure_Chart_of_MJRefresh"></a>The Class Structure Chart of MJRefresh
|
|
||||||

|
|
||||||
- `The class of red text` in the chart:You can use them directly
|
|
||||||
- The drop-down refresh control types
|
|
||||||
- Normal:`MJRefreshNormalHeader`
|
|
||||||
- Gif:`MJRefreshGifHeader`
|
|
||||||
- The pull to refresh control types
|
|
||||||
- Auto refresh
|
|
||||||
- Normal:`MJRefreshAutoNormalFooter`
|
|
||||||
- Gif:`MJRefreshAutoGifFooter`
|
|
||||||
- Auto Back
|
|
||||||
- Normal:`MJRefreshBackNormalFooter`
|
|
||||||
- Gif:`MJRefreshBackGifFooter`
|
|
||||||
|
|
||||||
- `The class of non-red text` in the chart:For inheritance,to use DIY the control of refresh
|
|
||||||
|
|
||||||
- About how to DIY the control of refresh,You can refer the Class in below Chart<br>
|
|
||||||
|
|
||||||
<img src="http://images0.cnblogs.com/blog2015/497279/201506/141358159107893.png" width="30%" height="30%">
|
|
||||||
|
|
||||||
## <a id="MJRefreshComponent.h"></a>MJRefreshComponent.h
|
|
||||||
```objc
|
|
||||||
/** The Base Class of refresh control */
|
|
||||||
@interface MJRefreshComponent : UIView
|
|
||||||
#pragma mark - Control the state of Refresh
|
|
||||||
|
|
||||||
/** BeginRefreshing */
|
|
||||||
- (void)beginRefreshing;
|
|
||||||
/** EndRefreshing */
|
|
||||||
- (void)endRefreshing;
|
|
||||||
/** IsRefreshing */
|
|
||||||
- (BOOL)isRefreshing;
|
|
||||||
|
|
||||||
#pragma mark - Other
|
|
||||||
/** According to the drag ratio to change alpha automatically */
|
|
||||||
@property (assign, nonatomic, getter=isAutomaticallyChangeAlpha) BOOL automaticallyChangeAlpha;
|
|
||||||
@end
|
|
||||||
```
|
|
||||||
|
|
||||||
## <a id="MJRefreshHeader.h"></a>MJRefreshHeader.h
|
|
||||||
```objc
|
|
||||||
@interface MJRefreshHeader : MJRefreshComponent
|
|
||||||
/** Creat header */
|
|
||||||
+ (instancetype)headerWithRefreshingBlock:(MJRefreshComponentRefreshingBlock)refreshingBlock;
|
|
||||||
/** Creat header */
|
|
||||||
+ (instancetype)headerWithRefreshingTarget:(id)target refreshingAction:(SEL)action;
|
|
||||||
|
|
||||||
/** This key is used to storage the time that the last time of drown-down successfully */
|
|
||||||
@property (copy, nonatomic) NSString *lastUpdatedTimeKey;
|
|
||||||
/** The last time of drown-down successfully */
|
|
||||||
@property (strong, nonatomic, readonly) NSDate *lastUpdatedTime;
|
|
||||||
|
|
||||||
/** Ignored scrollView contentInset top */
|
|
||||||
@property (assign, nonatomic) CGFloat ignoredScrollViewContentInsetTop;
|
|
||||||
@end
|
|
||||||
```
|
|
||||||
|
|
||||||
## <a id="MJRefreshFooter.h"></a>MJRefreshFooter.h
|
|
||||||
```objc
|
|
||||||
@interface MJRefreshFooter : MJRefreshComponent
|
|
||||||
/** Creat footer */
|
|
||||||
+ (instancetype)footerWithRefreshingBlock:(MJRefreshComponentRefreshingBlock)refreshingBlock;
|
|
||||||
/** Creat footer */
|
|
||||||
+ (instancetype)footerWithRefreshingTarget:(id)target refreshingAction:(SEL)action;
|
|
||||||
|
|
||||||
/** NoticeNoMoreData */
|
|
||||||
- (void)noticeNoMoreData;
|
|
||||||
/** ResetNoMoreData(Clear the status of NoMoreData ) */
|
|
||||||
- (void)resetNoMoreData;
|
|
||||||
|
|
||||||
/** Ignored scrollView contentInset bottom */
|
|
||||||
@property (assign, nonatomic) CGFloat ignoredScrollViewContentInsetBottom;
|
|
||||||
@end
|
|
||||||
```
|
|
||||||
|
|
||||||
## <a id="MJRefreshAutoFooter.h"></a>MJRefreshAutoFooter.h
|
|
||||||
```objc
|
|
||||||
@interface MJRefreshAutoFooter : MJRefreshFooter
|
|
||||||
/** Is Automatically Refresh(Default is Yes) */
|
|
||||||
@property (assign, nonatomic, getter=isAutomaticallyRefresh) BOOL automaticallyRefresh;
|
|
||||||
|
|
||||||
/** When there is much at the bottom of the control is automatically refresh(Default is 1.0,Is at the bottom of the control appears in full, will refresh automatically) */
|
|
||||||
@property (assign, nonatomic) CGFloat triggerAutomaticallyRefreshPercent;
|
|
||||||
@end
|
|
||||||
```
|
|
||||||
|
|
||||||
## <a id="MJRefreshTrailer.h"></a> MJRefreshTrailer.h
|
|
||||||
```objc
|
|
||||||
@interface MJRefreshTrailer : MJRefreshComponent
|
|
||||||
|
|
||||||
/** 创建trailer */
|
|
||||||
+ (instancetype)trailerWithRefreshingBlock:(MJRefreshComponentAction)refreshingBlock;
|
|
||||||
/** 创建trailer */
|
|
||||||
+ (instancetype)trailerWithRefreshingTarget:(id)target refreshingAction:(SEL)action;
|
|
||||||
|
|
||||||
/** 忽略多少scrollView的contentInset的right */
|
|
||||||
@property (assign, nonatomic) CGFloat ignoredScrollViewContentInsetRight;
|
|
||||||
|
|
||||||
@end
|
|
||||||
```
|
|
||||||
|
|
||||||
## <a id="Reference"></a>Reference
|
|
||||||
```objc
|
|
||||||
* Due to there are more functions of this framework,Don't write specific text describe its usage
|
|
||||||
* You can directly reference examples MJTableViewController、MJCollectionViewController、MJWebViewController,More intuitive and fast.
|
|
||||||
```
|
|
||||||
<img src="http://images0.cnblogs.com/blog2015/497279/201506/141345470048120.png" width="30%" height="30%">
|
|
||||||
|
|
||||||
## <a id="The_drop-down_refresh_01-Default"></a>The drop-down refresh 01-Default
|
|
||||||
|
|
||||||
```objc
|
|
||||||
self.tableView.mj_header = [MJRefreshNormalHeader headerWithRefreshingBlock:^{
|
|
||||||
//Call this Block When enter the refresh status automatically
|
|
||||||
}];
|
|
||||||
或
|
|
||||||
// Set the callback(Once you enter the refresh status,then call the action of target,that is call [self loadNewData])
|
|
||||||
self.tableView.mj_header = [MJRefreshNormalHeader headerWithRefreshingTarget:self refreshingAction:@selector(loadNewData)];
|
|
||||||
|
|
||||||
// Enter the refresh status immediately
|
|
||||||
[self.tableView.mj_header beginRefreshing];
|
|
||||||
```
|
|
||||||

|
|
||||||
|
|
||||||
## <a id="The_drop-down_refresh_02-Animation_image"></a>The drop-down refresh 02-Animation image
|
|
||||||
```objc
|
|
||||||
// Set the callback(一Once you enter the refresh status,then call the action of target,that is call [self loadNewData])
|
|
||||||
MJRefreshGifHeader *header = [MJRefreshGifHeader headerWithRefreshingTarget:self refreshingAction:@selector(loadNewData)];
|
|
||||||
// Set the ordinary state of animated images
|
|
||||||
[header setImages:idleImages forState:MJRefreshStateIdle];
|
|
||||||
// Set the pulling state of animated images(Enter the status of refreshing as soon as loosen)
|
|
||||||
[header setImages:pullingImages forState:MJRefreshStatePulling];
|
|
||||||
// Set the refreshing state of animated images
|
|
||||||
[header setImages:refreshingImages forState:MJRefreshStateRefreshing];
|
|
||||||
// Set header
|
|
||||||
self.tableView.mj_header = header;
|
|
||||||
```
|
|
||||||

|
|
||||||
|
|
||||||
## <a id="The_drop-down_refresh_03-Hide_the_time"></a>The drop-down refresh 03-Hide the time
|
|
||||||
```objc
|
|
||||||
// Hide the time
|
|
||||||
header.lastUpdatedTimeLabel.hidden = YES;
|
|
||||||
```
|
|
||||||

|
|
||||||
|
|
||||||
## <a id="The_drop-down_refresh_04-Hide_status_and_time"></a>The drop-down refresh 04-Hide status and time
|
|
||||||
```objc
|
|
||||||
// Hide the time
|
|
||||||
header.lastUpdatedTimeLabel.hidden = YES;
|
|
||||||
|
|
||||||
// Hide the status
|
|
||||||
header.stateLabel.hidden = YES;
|
|
||||||
```
|
|
||||||

|
|
||||||
|
|
||||||
## <a id="The_drop-down_refresh_05-DIY_title"></a>The drop-down refresh 05-DIY title
|
|
||||||
```objc
|
|
||||||
// Set title
|
|
||||||
[header setTitle:@"Pull down to refresh" forState:MJRefreshStateIdle];
|
|
||||||
[header setTitle:@"Release to refresh" forState:MJRefreshStatePulling];
|
|
||||||
[header setTitle:@"Loading ..." forState:MJRefreshStateRefreshing];
|
|
||||||
|
|
||||||
// Set font
|
|
||||||
header.stateLabel.font = [UIFont systemFontOfSize:15];
|
|
||||||
header.lastUpdatedTimeLabel.font = [UIFont systemFontOfSize:14];
|
|
||||||
|
|
||||||
// Set textColor
|
|
||||||
header.stateLabel.textColor = [UIColor redColor];
|
|
||||||
header.lastUpdatedTimeLabel.textColor = [UIColor blueColor];
|
|
||||||
```
|
|
||||||

|
|
||||||
|
|
||||||
## <a id="The_drop-down_refresh_06-DIY_the_control_of_refresh"></a>The drop-down refresh 06-DIY the control of refresh
|
|
||||||
```objc
|
|
||||||
self.tableView.mj_header = [MJDIYHeader headerWithRefreshingTarget:self refreshingAction:@selector(loadNewData)];
|
|
||||||
// Implementation reference to MJDIYHeader.h和MJDIYHeader.m
|
|
||||||
```
|
|
||||||

|
|
||||||
|
|
||||||
## <a id="The_pull_to_refresh_01-Default"></a>The pull to refresh 01-Default
|
|
||||||
```objc
|
|
||||||
self.tableView.mj_footer = [MJRefreshAutoNormalFooter footerWithRefreshingBlock:^{
|
|
||||||
//Call this Block When enter the refresh status automatically
|
|
||||||
}];
|
|
||||||
或
|
|
||||||
// Set the callback(Once you enter the refresh status,then call the action of target,that is call [self loadMoreData])
|
|
||||||
self.tableView.mj_footer = [MJRefreshAutoNormalFooter footerWithRefreshingTarget:self refreshingAction:@selector(loadMoreData)];
|
|
||||||
```
|
|
||||||

|
|
||||||
|
|
||||||
## <a id="The_pull_to_refresh_02-Animation_image"></a>The pull to refresh 02-Animation image
|
|
||||||
```objc
|
|
||||||
// Set the callback(Once you enter the refresh status,then call the action of target,that is call [self loadMoreData])
|
|
||||||
MJRefreshAutoGifFooter *footer = [MJRefreshAutoGifFooter footerWithRefreshingTarget:self refreshingAction:@selector(loadMoreData)];
|
|
||||||
|
|
||||||
// Set the refresh image
|
|
||||||
[footer setImages:refreshingImages forState:MJRefreshStateRefreshing];
|
|
||||||
|
|
||||||
// Set footer
|
|
||||||
self.tableView.mj_footer = footer;
|
|
||||||
```
|
|
||||||

|
|
||||||
|
|
||||||
## <a id="The_pull_to_refresh_03-Hide_the_title_of_refresh_status"></a>The pull to refresh 03-Hide the title of refresh status
|
|
||||||
```objc
|
|
||||||
// Hide the title of refresh status
|
|
||||||
footer.refreshingTitleHidden = YES;
|
|
||||||
// If does have not above method,then use footer.stateLabel.hidden = YES;
|
|
||||||
```
|
|
||||||

|
|
||||||
|
|
||||||
## <a id="The_pull_to_refresh_04-All_loaded"></a>The pull to refresh 04-All loaded
|
|
||||||
```objc
|
|
||||||
//Become the status of NoMoreData
|
|
||||||
[footer noticeNoMoreData];
|
|
||||||
```
|
|
||||||

|
|
||||||
|
|
||||||
## <a id="The_pull_to_refresh_05-DIY_title"></a>The pull to refresh 05-DIY title
|
|
||||||
```objc
|
|
||||||
// Set title
|
|
||||||
[footer setTitle:@"Click or drag up to refresh" forState:MJRefreshStateIdle];
|
|
||||||
[footer setTitle:@"Loading more ..." forState:MJRefreshStateRefreshing];
|
|
||||||
[footer setTitle:@"No more data" forState:MJRefreshStateNoMoreData];
|
|
||||||
|
|
||||||
// Set font
|
|
||||||
footer.stateLabel.font = [UIFont systemFontOfSize:17];
|
|
||||||
|
|
||||||
// Set textColor
|
|
||||||
footer.stateLabel.textColor = [UIColor blueColor];
|
|
||||||
```
|
|
||||||

|
|
||||||
|
|
||||||
## <a id="The_pull_to_refresh_06-Hidden_After_loaded"></a>The pull to refresh 06-Hidden After loaded
|
|
||||||
```objc
|
|
||||||
//Hidden current control of the pull to refresh
|
|
||||||
self.tableView.mj_footer.hidden = YES;
|
|
||||||
```
|
|
||||||

|
|
||||||
|
|
||||||
## <a id="The_pull_to_refresh_07-Automatic_back_of_the_pull01"></a>The pull to refresh 07-Automatic back of the pull01
|
|
||||||
```objc
|
|
||||||
self.tableView.mj_footer = [MJRefreshBackNormalFooter footerWithRefreshingTarget:self refreshingAction:@selector(loadMoreData)];
|
|
||||||
```
|
|
||||||

|
|
||||||
|
|
||||||
## <a id="The_pull_to_refresh_08-Automatic_back_of_the_pull02"></a>The pull to refresh 08-Automatic back of the pull02
|
|
||||||
```objc
|
|
||||||
MJRefreshBackGifFooter *footer = [MJRefreshBackGifFooter footerWithRefreshingTarget:self refreshingAction:@selector(loadMoreData)];
|
|
||||||
|
|
||||||
// Set the normal state of the animated image
|
|
||||||
[footer setImages:idleImages forState:MJRefreshStateIdle];
|
|
||||||
// Set the pulling state of animated images(Enter the status of refreshing as soon as loosen)
|
|
||||||
[footer setImages:pullingImages forState:MJRefreshStatePulling];
|
|
||||||
// Set the refreshing state of animated images
|
|
||||||
[footer setImages:refreshingImages forState:MJRefreshStateRefreshing];
|
|
||||||
|
|
||||||
// Set footer
|
|
||||||
self.tableView.mj_footer = footer;
|
|
||||||
```
|
|
||||||

|
|
||||||
|
|
||||||
## <a id="The_pull_to_refresh_09-DIY_the_control_of_refresh(Automatic_refresh)"></a>The pull to refresh 09-DIY the control of refresh(Automatic refresh)
|
|
||||||
```objc
|
|
||||||
self.tableView.mj_footer = [MJDIYAutoFooter footerWithRefreshingTarget:self refreshingAction:@selector(loadMoreData)];
|
|
||||||
// Implementation reference to MJDIYAutoFooter.h和MJDIYAutoFooter.m
|
|
||||||
```
|
|
||||||

|
|
||||||
|
|
||||||
## <a id="The_pull_to_refresh_10-DIY_the_control_of_refresh(Automatic_back)"></a>The pull to refresh 10-DIY the control of refresh(Automatic back)
|
|
||||||
```objc
|
|
||||||
self.tableView.mj_footer = [MJDIYBackFooter footerWithRefreshingTarget:self refreshingAction:@selector(loadMoreData)];
|
|
||||||
// Implementation reference to MJDIYBackFooter.h和MJDIYBackFooter.m
|
|
||||||
```
|
|
||||||

|
|
||||||
|
|
||||||
## <a id="UICollectionView01-The_pull_and_drop-down_refresh"></a>UICollectionView01-The pull and drop-down refresh
|
|
||||||
```objc
|
|
||||||
// The drop-down refresh
|
|
||||||
self.collectionView.mj_header = [MJRefreshNormalHeader headerWithRefreshingBlock:^{
|
|
||||||
//Call this Block When enter the refresh status automatically
|
|
||||||
}];
|
|
||||||
|
|
||||||
// The pull to refresh
|
|
||||||
self.collectionView.mj_footer = [MJRefreshAutoNormalFooter footerWithRefreshingBlock:^{
|
|
||||||
//Call this Block When enter the refresh status automatically
|
|
||||||
}];
|
|
||||||
```
|
|
||||||

|
|
||||||
|
|
||||||
## <a id="UICollectionView02-The_trailer_refresh"></a>UICollectionView02-The trailer refresh
|
|
||||||
```objc
|
|
||||||
// The trailer refresh
|
|
||||||
self.collectionView.mj_trailer = [MJRefreshNormalTrailer trailerWithRefreshingBlock:^{
|
|
||||||
//Call this Block When enter the refresh status automatically
|
|
||||||
}];
|
|
||||||
|
|
||||||
```
|
|
||||||

|
|
||||||
|
|
||||||
## <a id="WKWebView01-The_drop-down_refresh"></a>WKWebView01-The drop-down refresh
|
|
||||||
```objc
|
|
||||||
//Add the control of The drop-down refresh
|
|
||||||
self.webView.scrollView.mj_header = [MJRefreshNormalHeader headerWithRefreshingBlock:^{
|
|
||||||
//Call this Block When enter the refresh status automatically
|
|
||||||
}];
|
|
||||||
```
|
|
||||||

|
|
||||||
|
|
||||||
## Remind
|
|
||||||
* ARC
|
|
||||||
* iOS>=9.0
|
|
||||||
* iPhone \ iPad screen anyway
|
|
||||||
|
|
||||||
## 寻求志同道合的小伙伴
|
|
||||||
|
|
||||||
- 因本人工作忙,没有太多时间去维护MJRefresh,在此向广大框架使用者说声:非常抱歉!😞
|
|
||||||
- 现寻求志同道合的小伙伴一起维护此框架,有兴趣的小伙伴可以[发邮件](mailto:richermj123go@vip.qq.com)给我,非常感谢😊
|
|
||||||
- 如果一切OK,我将开放框架维护权限(github、pod等)
|
|
||||||
- 目前已经找到3位小伙伴(^-^)V
|
|
||||||
6
Pods/Manifest.lock
generated
6
Pods/Manifest.lock
generated
@ -6,13 +6,11 @@ PODS:
|
|||||||
- AMapFoundation-NO-IDFA (>= 1.8.7)
|
- AMapFoundation-NO-IDFA (>= 1.8.7)
|
||||||
- AMapSearch-NO-IDFA (9.7.5):
|
- AMapSearch-NO-IDFA (9.7.5):
|
||||||
- AMapFoundation-NO-IDFA (>= 1.8.0)
|
- AMapFoundation-NO-IDFA (>= 1.8.0)
|
||||||
- MJRefresh (3.7.9)
|
|
||||||
|
|
||||||
DEPENDENCIES:
|
DEPENDENCIES:
|
||||||
- AMap3DMap-NO-IDFA (~> 11.1)
|
- AMap3DMap-NO-IDFA (~> 11.1)
|
||||||
- AMapLocation-NO-IDFA (~> 2.11)
|
- AMapLocation-NO-IDFA (~> 2.11)
|
||||||
- AMapSearch-NO-IDFA (~> 9.7)
|
- AMapSearch-NO-IDFA (~> 9.7)
|
||||||
- MJRefresh (~> 3.7)
|
|
||||||
|
|
||||||
SPEC REPOS:
|
SPEC REPOS:
|
||||||
trunk:
|
trunk:
|
||||||
@ -20,15 +18,13 @@ SPEC REPOS:
|
|||||||
- AMapFoundation-NO-IDFA
|
- AMapFoundation-NO-IDFA
|
||||||
- AMapLocation-NO-IDFA
|
- AMapLocation-NO-IDFA
|
||||||
- AMapSearch-NO-IDFA
|
- AMapSearch-NO-IDFA
|
||||||
- MJRefresh
|
|
||||||
|
|
||||||
SPEC CHECKSUMS:
|
SPEC CHECKSUMS:
|
||||||
AMap3DMap-NO-IDFA: 393a24abb0451fed2daa4316c8d3d356a395f2be
|
AMap3DMap-NO-IDFA: 393a24abb0451fed2daa4316c8d3d356a395f2be
|
||||||
AMapFoundation-NO-IDFA: f48acbf6e74913dc6744581053f7d984f2432850
|
AMapFoundation-NO-IDFA: f48acbf6e74913dc6744581053f7d984f2432850
|
||||||
AMapLocation-NO-IDFA: 0fa6e7d5e42e10253f4437424d98966f53760862
|
AMapLocation-NO-IDFA: 0fa6e7d5e42e10253f4437424d98966f53760862
|
||||||
AMapSearch-NO-IDFA: 8e9d104032990a3b0cab66afb535299887c61047
|
AMapSearch-NO-IDFA: 8e9d104032990a3b0cab66afb535299887c61047
|
||||||
MJRefresh: ff9e531227924c84ce459338414550a05d2aea78
|
|
||||||
|
|
||||||
PODFILE CHECKSUM: dd39a238c7d1f1de8b61bcb07e20911bedae96b7
|
PODFILE CHECKSUM: baa972253fcebc312545f7592c48cbba632f1907
|
||||||
|
|
||||||
COCOAPODS: 1.16.2
|
COCOAPODS: 1.16.2
|
||||||
|
|||||||
1755
Pods/Pods.xcodeproj/project.pbxproj
generated
1755
Pods/Pods.xcodeproj/project.pbxproj
generated
File diff suppressed because it is too large
Load Diff
@ -1,26 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
|
||||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
|
||||||
<plist version="1.0">
|
|
||||||
<dict>
|
|
||||||
<key>CFBundleDevelopmentRegion</key>
|
|
||||||
<string>${PODS_DEVELOPMENT_LANGUAGE}</string>
|
|
||||||
<key>CFBundleExecutable</key>
|
|
||||||
<string>${EXECUTABLE_NAME}</string>
|
|
||||||
<key>CFBundleIdentifier</key>
|
|
||||||
<string>${PRODUCT_BUNDLE_IDENTIFIER}</string>
|
|
||||||
<key>CFBundleInfoDictionaryVersion</key>
|
|
||||||
<string>6.0</string>
|
|
||||||
<key>CFBundleName</key>
|
|
||||||
<string>${PRODUCT_NAME}</string>
|
|
||||||
<key>CFBundlePackageType</key>
|
|
||||||
<string>FMWK</string>
|
|
||||||
<key>CFBundleShortVersionString</key>
|
|
||||||
<string>3.7.9</string>
|
|
||||||
<key>CFBundleSignature</key>
|
|
||||||
<string>????</string>
|
|
||||||
<key>CFBundleVersion</key>
|
|
||||||
<string>${CURRENT_PROJECT_VERSION}</string>
|
|
||||||
<key>NSPrincipalClass</key>
|
|
||||||
<string></string>
|
|
||||||
</dict>
|
|
||||||
</plist>
|
|
||||||
@ -1,5 +0,0 @@
|
|||||||
#import <Foundation/Foundation.h>
|
|
||||||
@interface PodsDummy_MJRefresh : NSObject
|
|
||||||
@end
|
|
||||||
@implementation PodsDummy_MJRefresh
|
|
||||||
@end
|
|
||||||
@ -1,12 +0,0 @@
|
|||||||
#ifdef __OBJC__
|
|
||||||
#import <UIKit/UIKit.h>
|
|
||||||
#else
|
|
||||||
#ifndef FOUNDATION_EXPORT
|
|
||||||
#if defined(__cplusplus)
|
|
||||||
#define FOUNDATION_EXPORT extern "C"
|
|
||||||
#else
|
|
||||||
#define FOUNDATION_EXPORT extern
|
|
||||||
#endif
|
|
||||||
#endif
|
|
||||||
#endif
|
|
||||||
|
|
||||||
@ -1,41 +0,0 @@
|
|||||||
#ifdef __OBJC__
|
|
||||||
#import <UIKit/UIKit.h>
|
|
||||||
#else
|
|
||||||
#ifndef FOUNDATION_EXPORT
|
|
||||||
#if defined(__cplusplus)
|
|
||||||
#define FOUNDATION_EXPORT extern "C"
|
|
||||||
#else
|
|
||||||
#define FOUNDATION_EXPORT extern
|
|
||||||
#endif
|
|
||||||
#endif
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#import "MJRefreshAutoFooter.h"
|
|
||||||
#import "MJRefreshBackFooter.h"
|
|
||||||
#import "MJRefreshComponent.h"
|
|
||||||
#import "MJRefreshFooter.h"
|
|
||||||
#import "MJRefreshHeader.h"
|
|
||||||
#import "MJRefreshTrailer.h"
|
|
||||||
#import "MJRefreshAutoGifFooter.h"
|
|
||||||
#import "MJRefreshAutoNormalFooter.h"
|
|
||||||
#import "MJRefreshAutoStateFooter.h"
|
|
||||||
#import "MJRefreshBackGifFooter.h"
|
|
||||||
#import "MJRefreshBackNormalFooter.h"
|
|
||||||
#import "MJRefreshBackStateFooter.h"
|
|
||||||
#import "MJRefreshGifHeader.h"
|
|
||||||
#import "MJRefreshNormalHeader.h"
|
|
||||||
#import "MJRefreshStateHeader.h"
|
|
||||||
#import "MJRefreshNormalTrailer.h"
|
|
||||||
#import "MJRefreshStateTrailer.h"
|
|
||||||
#import "MJRefresh.h"
|
|
||||||
#import "MJRefreshConfig.h"
|
|
||||||
#import "MJRefreshConst.h"
|
|
||||||
#import "NSBundle+MJRefresh.h"
|
|
||||||
#import "UICollectionViewLayout+MJRefresh.h"
|
|
||||||
#import "UIScrollView+MJExtension.h"
|
|
||||||
#import "UIScrollView+MJRefresh.h"
|
|
||||||
#import "UIView+MJExtension.h"
|
|
||||||
|
|
||||||
FOUNDATION_EXPORT double MJRefreshVersionNumber;
|
|
||||||
FOUNDATION_EXPORT const unsigned char MJRefreshVersionString[];
|
|
||||||
|
|
||||||
@ -1,12 +0,0 @@
|
|||||||
CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = NO
|
|
||||||
CONFIGURATION_BUILD_DIR = ${PODS_CONFIGURATION_BUILD_DIR}/MJRefresh
|
|
||||||
GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1
|
|
||||||
PODS_BUILD_DIR = ${BUILD_DIR}
|
|
||||||
PODS_CONFIGURATION_BUILD_DIR = ${PODS_BUILD_DIR}/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME)
|
|
||||||
PODS_DEVELOPMENT_LANGUAGE = ${DEVELOPMENT_LANGUAGE}
|
|
||||||
PODS_ROOT = ${SRCROOT}
|
|
||||||
PODS_TARGET_SRCROOT = ${PODS_ROOT}/MJRefresh
|
|
||||||
PODS_XCFRAMEWORKS_BUILD_DIR = $(PODS_CONFIGURATION_BUILD_DIR)/XCFrameworkIntermediates
|
|
||||||
PRODUCT_BUNDLE_IDENTIFIER = org.cocoapods.${PRODUCT_NAME:rfc1034identifier}
|
|
||||||
SKIP_INSTALL = YES
|
|
||||||
USE_RECURSIVE_SCRIPT_INPUTS_IN_SCRIPT_PHASES = YES
|
|
||||||
@ -1,6 +0,0 @@
|
|||||||
framework module MJRefresh {
|
|
||||||
umbrella header "MJRefresh-umbrella.h"
|
|
||||||
|
|
||||||
export *
|
|
||||||
module * { export * }
|
|
||||||
}
|
|
||||||
@ -1,12 +0,0 @@
|
|||||||
CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = NO
|
|
||||||
CONFIGURATION_BUILD_DIR = ${PODS_CONFIGURATION_BUILD_DIR}/MJRefresh
|
|
||||||
GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1
|
|
||||||
PODS_BUILD_DIR = ${BUILD_DIR}
|
|
||||||
PODS_CONFIGURATION_BUILD_DIR = ${PODS_BUILD_DIR}/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME)
|
|
||||||
PODS_DEVELOPMENT_LANGUAGE = ${DEVELOPMENT_LANGUAGE}
|
|
||||||
PODS_ROOT = ${SRCROOT}
|
|
||||||
PODS_TARGET_SRCROOT = ${PODS_ROOT}/MJRefresh
|
|
||||||
PODS_XCFRAMEWORKS_BUILD_DIR = $(PODS_CONFIGURATION_BUILD_DIR)/XCFrameworkIntermediates
|
|
||||||
PRODUCT_BUNDLE_IDENTIFIER = org.cocoapods.${PRODUCT_NAME:rfc1034identifier}
|
|
||||||
SKIP_INSTALL = YES
|
|
||||||
USE_RECURSIVE_SCRIPT_INPUTS_IN_SCRIPT_PHASES = YES
|
|
||||||
@ -1,24 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
|
||||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
|
||||||
<plist version="1.0">
|
|
||||||
<dict>
|
|
||||||
<key>CFBundleDevelopmentRegion</key>
|
|
||||||
<string>${PODS_DEVELOPMENT_LANGUAGE}</string>
|
|
||||||
<key>CFBundleIdentifier</key>
|
|
||||||
<string>${PRODUCT_BUNDLE_IDENTIFIER}</string>
|
|
||||||
<key>CFBundleInfoDictionaryVersion</key>
|
|
||||||
<string>6.0</string>
|
|
||||||
<key>CFBundleName</key>
|
|
||||||
<string>${PRODUCT_NAME}</string>
|
|
||||||
<key>CFBundlePackageType</key>
|
|
||||||
<string>BNDL</string>
|
|
||||||
<key>CFBundleShortVersionString</key>
|
|
||||||
<string>3.7.9</string>
|
|
||||||
<key>CFBundleSignature</key>
|
|
||||||
<string>????</string>
|
|
||||||
<key>CFBundleVersion</key>
|
|
||||||
<string>1</string>
|
|
||||||
<key>NSPrincipalClass</key>
|
|
||||||
<string></string>
|
|
||||||
</dict>
|
|
||||||
</plist>
|
|
||||||
@ -20,27 +20,4 @@ Copyright © 2014 AutoNavi. All Rights Reserved.
|
|||||||
|
|
||||||
Copyright © 2014 AutoNavi. All Rights Reserved.
|
Copyright © 2014 AutoNavi. All Rights Reserved.
|
||||||
|
|
||||||
|
|
||||||
## MJRefresh
|
|
||||||
|
|
||||||
Copyright (c) 2013-2015 MJRefresh (https://github.com/CoderMJLee/MJRefresh)
|
|
||||||
|
|
||||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
||||||
of this software and associated documentation files (the "Software"), to deal
|
|
||||||
in the Software without restriction, including without limitation the rights
|
|
||||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
||||||
copies of the Software, and to permit persons to whom the Software is
|
|
||||||
furnished to do so, subject to the following conditions:
|
|
||||||
|
|
||||||
The above copyright notice and this permission notice shall be included in
|
|
||||||
all copies or substantial portions of the Software.
|
|
||||||
|
|
||||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
||||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
||||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
||||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
||||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
||||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
|
||||||
THE SOFTWARE.
|
|
||||||
|
|
||||||
Generated by CocoaPods - https://cocoapods.org
|
Generated by CocoaPods - https://cocoapods.org
|
||||||
|
|||||||
@ -56,35 +56,6 @@
|
|||||||
<key>Type</key>
|
<key>Type</key>
|
||||||
<string>PSGroupSpecifier</string>
|
<string>PSGroupSpecifier</string>
|
||||||
</dict>
|
</dict>
|
||||||
<dict>
|
|
||||||
<key>FooterText</key>
|
|
||||||
<string>Copyright (c) 2013-2015 MJRefresh (https://github.com/CoderMJLee/MJRefresh)
|
|
||||||
|
|
||||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
||||||
of this software and associated documentation files (the "Software"), to deal
|
|
||||||
in the Software without restriction, including without limitation the rights
|
|
||||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
||||||
copies of the Software, and to permit persons to whom the Software is
|
|
||||||
furnished to do so, subject to the following conditions:
|
|
||||||
|
|
||||||
The above copyright notice and this permission notice shall be included in
|
|
||||||
all copies or substantial portions of the Software.
|
|
||||||
|
|
||||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
||||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
||||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
||||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
||||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
||||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
|
||||||
THE SOFTWARE.
|
|
||||||
</string>
|
|
||||||
<key>License</key>
|
|
||||||
<string>MIT</string>
|
|
||||||
<key>Title</key>
|
|
||||||
<string>MJRefresh</string>
|
|
||||||
<key>Type</key>
|
|
||||||
<string>PSGroupSpecifier</string>
|
|
||||||
</dict>
|
|
||||||
<dict>
|
<dict>
|
||||||
<key>FooterText</key>
|
<key>FooterText</key>
|
||||||
<string>Generated by CocoaPods - https://cocoapods.org</string>
|
<string>Generated by CocoaPods - https://cocoapods.org</string>
|
||||||
|
|||||||
@ -1,11 +1,10 @@
|
|||||||
ARCHS = $(ARCHS_STANDARD)
|
ARCHS = $(ARCHS_STANDARD)
|
||||||
CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = NO
|
CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = NO
|
||||||
FRAMEWORK_SEARCH_PATHS = $(inherited) "${PODS_CONFIGURATION_BUILD_DIR}/MJRefresh" "${PODS_ROOT}/AMap3DMap-NO-IDFA" "${PODS_ROOT}/AMapFoundation-NO-IDFA" "${PODS_ROOT}/AMapLocation-NO-IDFA" "${PODS_ROOT}/AMapSearch-NO-IDFA"
|
FRAMEWORK_SEARCH_PATHS = $(inherited) "${PODS_ROOT}/AMap3DMap-NO-IDFA" "${PODS_ROOT}/AMapFoundation-NO-IDFA" "${PODS_ROOT}/AMapLocation-NO-IDFA" "${PODS_ROOT}/AMapSearch-NO-IDFA"
|
||||||
GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1
|
GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1
|
||||||
HEADER_SEARCH_PATHS = $(inherited) "${PODS_CONFIGURATION_BUILD_DIR}/MJRefresh/MJRefresh.framework/Headers"
|
|
||||||
LD_RUNPATH_SEARCH_PATHS = $(inherited) '@executable_path/Frameworks' '@loader_path/Frameworks'
|
LD_RUNPATH_SEARCH_PATHS = $(inherited) '@executable_path/Frameworks' '@loader_path/Frameworks'
|
||||||
OTHER_LDFLAGS = $(inherited) -ObjC -l"c++" -l"z" -framework "AMapFoundationKit" -framework "AMapLocationKit" -framework "AMapSearchKit" -framework "CoreGraphics" -framework "CoreLocation" -framework "CoreTelephony" -framework "CoreText" -framework "ExternalAccessory" -framework "GLKit" -framework "MAMapKit" -framework "MJRefresh" -framework "OpenGLES" -framework "QuartzCore" -framework "Security" -framework "SystemConfiguration"
|
OTHER_LDFLAGS = $(inherited) -ObjC -l"c++" -l"z" -framework "AMapFoundationKit" -framework "AMapLocationKit" -framework "AMapSearchKit" -framework "CoreGraphics" -framework "CoreLocation" -framework "CoreTelephony" -framework "CoreText" -framework "ExternalAccessory" -framework "GLKit" -framework "MAMapKit" -framework "OpenGLES" -framework "QuartzCore" -framework "Security" -framework "SystemConfiguration"
|
||||||
OTHER_MODULE_VERIFIER_FLAGS = $(inherited) "-F${PODS_CONFIGURATION_BUILD_DIR}/AMap3DMap-NO-IDFA" "-F${PODS_CONFIGURATION_BUILD_DIR}/AMapFoundation-NO-IDFA" "-F${PODS_CONFIGURATION_BUILD_DIR}/AMapLocation-NO-IDFA" "-F${PODS_CONFIGURATION_BUILD_DIR}/AMapSearch-NO-IDFA" "-F${PODS_CONFIGURATION_BUILD_DIR}/MJRefresh"
|
OTHER_MODULE_VERIFIER_FLAGS = $(inherited) "-F${PODS_CONFIGURATION_BUILD_DIR}/AMap3DMap-NO-IDFA" "-F${PODS_CONFIGURATION_BUILD_DIR}/AMapFoundation-NO-IDFA" "-F${PODS_CONFIGURATION_BUILD_DIR}/AMapLocation-NO-IDFA" "-F${PODS_CONFIGURATION_BUILD_DIR}/AMapSearch-NO-IDFA"
|
||||||
PODS_BUILD_DIR = ${BUILD_DIR}
|
PODS_BUILD_DIR = ${BUILD_DIR}
|
||||||
PODS_CONFIGURATION_BUILD_DIR = ${PODS_BUILD_DIR}/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME)
|
PODS_CONFIGURATION_BUILD_DIR = ${PODS_BUILD_DIR}/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME)
|
||||||
PODS_PODFILE_DIR_PATH = ${SRCROOT}/.
|
PODS_PODFILE_DIR_PATH = ${SRCROOT}/.
|
||||||
|
|||||||
@ -1,11 +1,10 @@
|
|||||||
ARCHS = $(ARCHS_STANDARD)
|
ARCHS = $(ARCHS_STANDARD)
|
||||||
CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = NO
|
CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = NO
|
||||||
FRAMEWORK_SEARCH_PATHS = $(inherited) "${PODS_CONFIGURATION_BUILD_DIR}/MJRefresh" "${PODS_ROOT}/AMap3DMap-NO-IDFA" "${PODS_ROOT}/AMapFoundation-NO-IDFA" "${PODS_ROOT}/AMapLocation-NO-IDFA" "${PODS_ROOT}/AMapSearch-NO-IDFA"
|
FRAMEWORK_SEARCH_PATHS = $(inherited) "${PODS_ROOT}/AMap3DMap-NO-IDFA" "${PODS_ROOT}/AMapFoundation-NO-IDFA" "${PODS_ROOT}/AMapLocation-NO-IDFA" "${PODS_ROOT}/AMapSearch-NO-IDFA"
|
||||||
GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1
|
GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1
|
||||||
HEADER_SEARCH_PATHS = $(inherited) "${PODS_CONFIGURATION_BUILD_DIR}/MJRefresh/MJRefresh.framework/Headers"
|
|
||||||
LD_RUNPATH_SEARCH_PATHS = $(inherited) '@executable_path/Frameworks' '@loader_path/Frameworks'
|
LD_RUNPATH_SEARCH_PATHS = $(inherited) '@executable_path/Frameworks' '@loader_path/Frameworks'
|
||||||
OTHER_LDFLAGS = $(inherited) -ObjC -l"c++" -l"z" -framework "AMapFoundationKit" -framework "AMapLocationKit" -framework "AMapSearchKit" -framework "CoreGraphics" -framework "CoreLocation" -framework "CoreTelephony" -framework "CoreText" -framework "ExternalAccessory" -framework "GLKit" -framework "MAMapKit" -framework "MJRefresh" -framework "OpenGLES" -framework "QuartzCore" -framework "Security" -framework "SystemConfiguration"
|
OTHER_LDFLAGS = $(inherited) -ObjC -l"c++" -l"z" -framework "AMapFoundationKit" -framework "AMapLocationKit" -framework "AMapSearchKit" -framework "CoreGraphics" -framework "CoreLocation" -framework "CoreTelephony" -framework "CoreText" -framework "ExternalAccessory" -framework "GLKit" -framework "MAMapKit" -framework "OpenGLES" -framework "QuartzCore" -framework "Security" -framework "SystemConfiguration"
|
||||||
OTHER_MODULE_VERIFIER_FLAGS = $(inherited) "-F${PODS_CONFIGURATION_BUILD_DIR}/AMap3DMap-NO-IDFA" "-F${PODS_CONFIGURATION_BUILD_DIR}/AMapFoundation-NO-IDFA" "-F${PODS_CONFIGURATION_BUILD_DIR}/AMapLocation-NO-IDFA" "-F${PODS_CONFIGURATION_BUILD_DIR}/AMapSearch-NO-IDFA" "-F${PODS_CONFIGURATION_BUILD_DIR}/MJRefresh"
|
OTHER_MODULE_VERIFIER_FLAGS = $(inherited) "-F${PODS_CONFIGURATION_BUILD_DIR}/AMap3DMap-NO-IDFA" "-F${PODS_CONFIGURATION_BUILD_DIR}/AMapFoundation-NO-IDFA" "-F${PODS_CONFIGURATION_BUILD_DIR}/AMapLocation-NO-IDFA" "-F${PODS_CONFIGURATION_BUILD_DIR}/AMapSearch-NO-IDFA"
|
||||||
PODS_BUILD_DIR = ${BUILD_DIR}
|
PODS_BUILD_DIR = ${BUILD_DIR}
|
||||||
PODS_CONFIGURATION_BUILD_DIR = ${PODS_BUILD_DIR}/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME)
|
PODS_CONFIGURATION_BUILD_DIR = ${PODS_BUILD_DIR}/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME)
|
||||||
PODS_PODFILE_DIR_PATH = ${SRCROOT}/.
|
PODS_PODFILE_DIR_PATH = ${SRCROOT}/.
|
||||||
|
|||||||
@ -1,9 +1,8 @@
|
|||||||
ARCHS = $(ARCHS_STANDARD)
|
ARCHS = $(ARCHS_STANDARD)
|
||||||
CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = NO
|
CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = NO
|
||||||
FRAMEWORK_SEARCH_PATHS = $(inherited) "${PODS_CONFIGURATION_BUILD_DIR}/MJRefresh" "${PODS_ROOT}/AMap3DMap-NO-IDFA" "${PODS_ROOT}/AMapFoundation-NO-IDFA" "${PODS_ROOT}/AMapLocation-NO-IDFA" "${PODS_ROOT}/AMapSearch-NO-IDFA"
|
FRAMEWORK_SEARCH_PATHS = $(inherited) "${PODS_ROOT}/AMap3DMap-NO-IDFA" "${PODS_ROOT}/AMapFoundation-NO-IDFA" "${PODS_ROOT}/AMapLocation-NO-IDFA" "${PODS_ROOT}/AMapSearch-NO-IDFA"
|
||||||
GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1
|
GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1
|
||||||
HEADER_SEARCH_PATHS = $(inherited) "${PODS_CONFIGURATION_BUILD_DIR}/MJRefresh/MJRefresh.framework/Headers"
|
OTHER_LDFLAGS = $(inherited) -l"c++" -l"z" -framework "CoreGraphics" -framework "CoreLocation" -framework "CoreTelephony" -framework "CoreText" -framework "ExternalAccessory" -framework "GLKit" -framework "OpenGLES" -framework "QuartzCore" -framework "Security" -framework "SystemConfiguration"
|
||||||
OTHER_LDFLAGS = $(inherited) -l"c++" -l"z" -framework "CoreGraphics" -framework "CoreLocation" -framework "CoreTelephony" -framework "CoreText" -framework "ExternalAccessory" -framework "GLKit" -framework "MJRefresh" -framework "OpenGLES" -framework "QuartzCore" -framework "Security" -framework "SystemConfiguration"
|
|
||||||
PODS_BUILD_DIR = ${BUILD_DIR}
|
PODS_BUILD_DIR = ${BUILD_DIR}
|
||||||
PODS_CONFIGURATION_BUILD_DIR = ${PODS_BUILD_DIR}/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME)
|
PODS_CONFIGURATION_BUILD_DIR = ${PODS_BUILD_DIR}/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME)
|
||||||
PODS_PODFILE_DIR_PATH = ${SRCROOT}/.
|
PODS_PODFILE_DIR_PATH = ${SRCROOT}/.
|
||||||
|
|||||||
@ -1,9 +1,8 @@
|
|||||||
ARCHS = $(ARCHS_STANDARD)
|
ARCHS = $(ARCHS_STANDARD)
|
||||||
CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = NO
|
CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = NO
|
||||||
FRAMEWORK_SEARCH_PATHS = $(inherited) "${PODS_CONFIGURATION_BUILD_DIR}/MJRefresh" "${PODS_ROOT}/AMap3DMap-NO-IDFA" "${PODS_ROOT}/AMapFoundation-NO-IDFA" "${PODS_ROOT}/AMapLocation-NO-IDFA" "${PODS_ROOT}/AMapSearch-NO-IDFA"
|
FRAMEWORK_SEARCH_PATHS = $(inherited) "${PODS_ROOT}/AMap3DMap-NO-IDFA" "${PODS_ROOT}/AMapFoundation-NO-IDFA" "${PODS_ROOT}/AMapLocation-NO-IDFA" "${PODS_ROOT}/AMapSearch-NO-IDFA"
|
||||||
GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1
|
GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1
|
||||||
HEADER_SEARCH_PATHS = $(inherited) "${PODS_CONFIGURATION_BUILD_DIR}/MJRefresh/MJRefresh.framework/Headers"
|
OTHER_LDFLAGS = $(inherited) -l"c++" -l"z" -framework "CoreGraphics" -framework "CoreLocation" -framework "CoreTelephony" -framework "CoreText" -framework "ExternalAccessory" -framework "GLKit" -framework "OpenGLES" -framework "QuartzCore" -framework "Security" -framework "SystemConfiguration"
|
||||||
OTHER_LDFLAGS = $(inherited) -l"c++" -l"z" -framework "CoreGraphics" -framework "CoreLocation" -framework "CoreTelephony" -framework "CoreText" -framework "ExternalAccessory" -framework "GLKit" -framework "MJRefresh" -framework "OpenGLES" -framework "QuartzCore" -framework "Security" -framework "SystemConfiguration"
|
|
||||||
PODS_BUILD_DIR = ${BUILD_DIR}
|
PODS_BUILD_DIR = ${BUILD_DIR}
|
||||||
PODS_CONFIGURATION_BUILD_DIR = ${PODS_BUILD_DIR}/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME)
|
PODS_CONFIGURATION_BUILD_DIR = ${PODS_BUILD_DIR}/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME)
|
||||||
PODS_PODFILE_DIR_PATH = ${SRCROOT}/.
|
PODS_PODFILE_DIR_PATH = ${SRCROOT}/.
|
||||||
|
|||||||
@ -64,11 +64,15 @@
|
|||||||
};
|
};
|
||||||
A00000022FE9000000000002 /* suixinkanTests */ = {
|
A00000022FE9000000000002 /* suixinkanTests */ = {
|
||||||
isa = PBXFileSystemSynchronizedRootGroup;
|
isa = PBXFileSystemSynchronizedRootGroup;
|
||||||
|
exceptions = (
|
||||||
|
);
|
||||||
path = suixinkanTests;
|
path = suixinkanTests;
|
||||||
sourceTree = "<group>";
|
sourceTree = "<group>";
|
||||||
};
|
};
|
||||||
B00000022FEF000000000002 /* suixinkanUITests */ = {
|
B00000022FEF000000000002 /* suixinkanUITests */ = {
|
||||||
isa = PBXFileSystemSynchronizedRootGroup;
|
isa = PBXFileSystemSynchronizedRootGroup;
|
||||||
|
exceptions = (
|
||||||
|
);
|
||||||
path = suixinkanUITests;
|
path = suixinkanUITests;
|
||||||
sourceTree = "<group>";
|
sourceTree = "<group>";
|
||||||
};
|
};
|
||||||
@ -158,7 +162,6 @@
|
|||||||
939AC7932FE3F832004B22E4 /* Frameworks */,
|
939AC7932FE3F832004B22E4 /* Frameworks */,
|
||||||
939AC7942FE3F832004B22E4 /* Resources */,
|
939AC7942FE3F832004B22E4 /* Resources */,
|
||||||
6F866A031F8EAF0CA7CF0E12 /* [CP] Copy Pods Resources */,
|
6F866A031F8EAF0CA7CF0E12 /* [CP] Copy Pods Resources */,
|
||||||
68DE7BABFCA72C541E0F1F82 /* [CP] Embed Pods Frameworks */,
|
|
||||||
);
|
);
|
||||||
buildRules = (
|
buildRules = (
|
||||||
);
|
);
|
||||||
@ -316,27 +319,6 @@
|
|||||||
shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n";
|
shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n";
|
||||||
showEnvVarsInLog = 0;
|
showEnvVarsInLog = 0;
|
||||||
};
|
};
|
||||||
68DE7BABFCA72C541E0F1F82 /* [CP] Embed Pods Frameworks */ = {
|
|
||||||
isa = PBXShellScriptBuildPhase;
|
|
||||||
buildActionMask = 2147483647;
|
|
||||||
files = (
|
|
||||||
);
|
|
||||||
inputFileListPaths = (
|
|
||||||
"${PODS_ROOT}/Target Support Files/Pods-suixinkan/Pods-suixinkan-frameworks-${CONFIGURATION}-input-files.xcfilelist",
|
|
||||||
);
|
|
||||||
inputPaths = (
|
|
||||||
);
|
|
||||||
name = "[CP] Embed Pods Frameworks";
|
|
||||||
outputFileListPaths = (
|
|
||||||
"${PODS_ROOT}/Target Support Files/Pods-suixinkan/Pods-suixinkan-frameworks-${CONFIGURATION}-output-files.xcfilelist",
|
|
||||||
);
|
|
||||||
outputPaths = (
|
|
||||||
);
|
|
||||||
runOnlyForDeploymentPostprocessing = 0;
|
|
||||||
shellPath = /bin/sh;
|
|
||||||
shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-suixinkan/Pods-suixinkan-frameworks.sh\"\n";
|
|
||||||
showEnvVarsInLog = 0;
|
|
||||||
};
|
|
||||||
6F866A031F8EAF0CA7CF0E12 /* [CP] Copy Pods Resources */ = {
|
6F866A031F8EAF0CA7CF0E12 /* [CP] Copy Pods Resources */ = {
|
||||||
isa = PBXShellScriptBuildPhase;
|
isa = PBXShellScriptBuildPhase;
|
||||||
buildActionMask = 2147483647;
|
buildActionMask = 2147483647;
|
||||||
@ -345,14 +327,10 @@
|
|||||||
inputFileListPaths = (
|
inputFileListPaths = (
|
||||||
"${PODS_ROOT}/Target Support Files/Pods-suixinkan/Pods-suixinkan-resources-${CONFIGURATION}-input-files.xcfilelist",
|
"${PODS_ROOT}/Target Support Files/Pods-suixinkan/Pods-suixinkan-resources-${CONFIGURATION}-input-files.xcfilelist",
|
||||||
);
|
);
|
||||||
inputPaths = (
|
|
||||||
);
|
|
||||||
name = "[CP] Copy Pods Resources";
|
name = "[CP] Copy Pods Resources";
|
||||||
outputFileListPaths = (
|
outputFileListPaths = (
|
||||||
"${PODS_ROOT}/Target Support Files/Pods-suixinkan/Pods-suixinkan-resources-${CONFIGURATION}-output-files.xcfilelist",
|
"${PODS_ROOT}/Target Support Files/Pods-suixinkan/Pods-suixinkan-resources-${CONFIGURATION}-output-files.xcfilelist",
|
||||||
);
|
);
|
||||||
outputPaths = (
|
|
||||||
);
|
|
||||||
runOnlyForDeploymentPostprocessing = 0;
|
runOnlyForDeploymentPostprocessing = 0;
|
||||||
shellPath = /bin/sh;
|
shellPath = /bin/sh;
|
||||||
shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-suixinkan/Pods-suixinkan-resources.sh\"\n";
|
shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-suixinkan/Pods-suixinkan-resources.sh\"\n";
|
||||||
|
|||||||
@ -14,7 +14,6 @@ struct suixinkanApp: App {
|
|||||||
|
|
||||||
init() {
|
init() {
|
||||||
AppUITestLaunchState.resetIfNeeded()
|
AppUITestLaunchState.resetIfNeeded()
|
||||||
MJRefreshSupport.configure()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
var body: some Scene {
|
var body: some Scene {
|
||||||
|
|||||||
@ -91,17 +91,3 @@ Toast UI 是顶部全宽横幅,背景使用不透明主色并延伸到顶部
|
|||||||
- 上传进度只用于当前页面展示。
|
- 上传进度只用于当前页面展示。
|
||||||
|
|
||||||
网络图片统一使用 `RemoteImage` / `RemoteAvatarImage`,内部由 Kingfisher 负责下载和缓存。业务页面不要再直接使用 `AsyncImage` 加载网络图片。
|
网络图片统一使用 `RemoteImage` / `RemoteAvatarImage`,内部由 Kingfisher 负责下载和缓存。业务页面不要再直接使用 `AsyncImage` 加载网络图片。
|
||||||
|
|
||||||
### MJRefresh
|
|
||||||
|
|
||||||
项目通过 CocoaPods 集成 `MJRefresh`,并在 `Core/Design/MJRefreshSupport.swift` 提供 SwiftUI 桥接能力。App 启动时会调用 `MJRefreshSupport.configure()` 设置默认中文文案。
|
|
||||||
|
|
||||||
SwiftUI 列表如需使用 MJRefresh 风格的下拉刷新或上拉加载,可在 `ScrollView` / `List` 上使用:
|
|
||||||
|
|
||||||
- `.mjRefresh(onRefresh:onLoadMore:hasMore:)`
|
|
||||||
- `.mjRefreshHeader { ... }`
|
|
||||||
- `.mjRefreshFooter(hasMore:action:)`
|
|
||||||
|
|
||||||
桥接层会自动定位底层 `UIScrollView` 并绑定 header/footer。页面仍应把真正的数据加载逻辑放在 ViewModel 中,modifier 只负责触发刷新和结束 MJRefresh 动画。
|
|
||||||
|
|
||||||
若页面已经使用 SwiftUI 原生 `.refreshable`,不要重复叠加 MJRefresh 下拉刷新,避免双刷新冲突。
|
|
||||||
|
|||||||
@ -1,205 +0,0 @@
|
|||||||
//
|
|
||||||
// MJRefreshSupport.swift
|
|
||||||
// suixinkan
|
|
||||||
//
|
|
||||||
// Created by Codex on 2026/6/26.
|
|
||||||
//
|
|
||||||
|
|
||||||
import MJRefresh
|
|
||||||
import SwiftUI
|
|
||||||
import UIKit
|
|
||||||
|
|
||||||
/// MJRefresh 全局配置入口,负责初始化第三方库默认行为。
|
|
||||||
enum MJRefreshSupport {
|
|
||||||
/// 配置 MJRefresh 默认语言等全局选项。
|
|
||||||
static func configure() {
|
|
||||||
MJRefreshConfig.default.languageCode = "zh-Hans"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// MJRefresh 绑定配置,描述下拉刷新和上拉加载行为。
|
|
||||||
struct MJRefreshBindingConfiguration {
|
|
||||||
var onRefresh: (() async -> Void)?
|
|
||||||
var onLoadMore: (() async -> Void)?
|
|
||||||
var hasMore = false
|
|
||||||
|
|
||||||
/// 判断当前配置是否包含任意刷新能力。
|
|
||||||
var isEmpty: Bool {
|
|
||||||
onRefresh == nil && onLoadMore == nil
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
extension View {
|
|
||||||
/// 为 SwiftUI `ScrollView` / `List` 绑定 MJRefresh 下拉刷新与上拉加载。
|
|
||||||
func mjRefresh(
|
|
||||||
onRefresh: (() async -> Void)? = nil,
|
|
||||||
onLoadMore: (() async -> Void)? = nil,
|
|
||||||
hasMore: Bool = false
|
|
||||||
) -> some View {
|
|
||||||
modifier(
|
|
||||||
MJRefreshModifier(
|
|
||||||
configuration: MJRefreshBindingConfiguration(
|
|
||||||
onRefresh: onRefresh,
|
|
||||||
onLoadMore: onLoadMore,
|
|
||||||
hasMore: hasMore
|
|
||||||
)
|
|
||||||
)
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
/// 为 SwiftUI 滚动容器仅绑定 MJRefresh 下拉刷新。
|
|
||||||
func mjRefreshHeader(_ action: @escaping () async -> Void) -> some View {
|
|
||||||
mjRefresh(onRefresh: action)
|
|
||||||
}
|
|
||||||
|
|
||||||
/// 为 SwiftUI 滚动容器仅绑定 MJRefresh 上拉加载更多。
|
|
||||||
func mjRefreshFooter(hasMore: Bool, action: @escaping () async -> Void) -> some View {
|
|
||||||
mjRefresh(onLoadMore: action, hasMore: hasMore)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// SwiftUI 与 MJRefresh 的桥接修饰符,通过锚点视图定位底层 `UIScrollView`。
|
|
||||||
private struct MJRefreshModifier: ViewModifier {
|
|
||||||
let configuration: MJRefreshBindingConfiguration
|
|
||||||
|
|
||||||
func body(content: Content) -> some View {
|
|
||||||
content.background {
|
|
||||||
MJRefreshScrollAnchor(configuration: configuration)
|
|
||||||
.frame(width: 0, height: 0)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// 透明锚点视图,用于在 SwiftUI 滚动容器中查找并绑定 MJRefresh。
|
|
||||||
private struct MJRefreshScrollAnchor: UIViewRepresentable {
|
|
||||||
let configuration: MJRefreshBindingConfiguration
|
|
||||||
|
|
||||||
func makeCoordinator() -> Coordinator {
|
|
||||||
Coordinator()
|
|
||||||
}
|
|
||||||
|
|
||||||
func makeUIView(context: Context) -> UIView {
|
|
||||||
let view = UIView(frame: .zero)
|
|
||||||
view.isUserInteractionEnabled = false
|
|
||||||
view.backgroundColor = .clear
|
|
||||||
return view
|
|
||||||
}
|
|
||||||
|
|
||||||
func updateUIView(_ uiView: UIView, context: Context) {
|
|
||||||
context.coordinator.scheduleApply(configuration: configuration, from: uiView)
|
|
||||||
}
|
|
||||||
|
|
||||||
static func dismantleUIView(_ uiView: UIView, coordinator: Coordinator) {
|
|
||||||
coordinator.unbind(from: uiView)
|
|
||||||
}
|
|
||||||
|
|
||||||
/// MJRefresh 绑定协调器,负责创建、更新和释放 header/footer。
|
|
||||||
final class Coordinator {
|
|
||||||
private weak var scrollView: UIScrollView?
|
|
||||||
private var configuration = MJRefreshBindingConfiguration()
|
|
||||||
private var pendingApply: DispatchWorkItem?
|
|
||||||
|
|
||||||
/// 延迟到下一 runloop 绑定,确保 SwiftUI 已创建底层滚动视图。
|
|
||||||
func scheduleApply(configuration: MJRefreshBindingConfiguration, from anchorView: UIView) {
|
|
||||||
pendingApply?.cancel()
|
|
||||||
let workItem = DispatchWorkItem { [weak self, weak anchorView] in
|
|
||||||
guard let self, let anchorView else { return }
|
|
||||||
guard let scrollView = anchorView.enclosingScrollView else { return }
|
|
||||||
self.apply(configuration: configuration, to: scrollView)
|
|
||||||
}
|
|
||||||
pendingApply = workItem
|
|
||||||
DispatchQueue.main.async(execute: workItem)
|
|
||||||
}
|
|
||||||
|
|
||||||
/// 将最新配置应用到指定滚动视图。
|
|
||||||
private func apply(configuration: MJRefreshBindingConfiguration, to scrollView: UIScrollView) {
|
|
||||||
self.scrollView = scrollView
|
|
||||||
self.configuration = configuration
|
|
||||||
|
|
||||||
if configuration.isEmpty {
|
|
||||||
scrollView.mj_header = nil
|
|
||||||
scrollView.mj_footer = nil
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
if let onRefresh = configuration.onRefresh {
|
|
||||||
if scrollView.mj_header == nil {
|
|
||||||
scrollView.mj_header = MJRefreshNormalHeader { [weak self] in
|
|
||||||
self?.performHeaderRefresh(onRefresh)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
scrollView.mj_header = nil
|
|
||||||
}
|
|
||||||
|
|
||||||
if let onLoadMore = configuration.onLoadMore {
|
|
||||||
if scrollView.mj_footer == nil {
|
|
||||||
scrollView.mj_footer = MJRefreshAutoNormalFooter { [weak self] in
|
|
||||||
self?.performFooterLoadMore(onLoadMore)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
updateFooterState(hasMore: configuration.hasMore)
|
|
||||||
} else {
|
|
||||||
scrollView.mj_footer = nil
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// 执行下拉刷新并在完成后结束 MJRefresh 动画。
|
|
||||||
private func performHeaderRefresh(_ action: @escaping () async -> Void) {
|
|
||||||
Task { @MainActor in
|
|
||||||
await action()
|
|
||||||
await scrollView?.mj_header?.endRefreshing()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// 执行上拉加载并在完成后结束 MJRefresh 动画。
|
|
||||||
private func performFooterLoadMore(_ action: @escaping () async -> Void) {
|
|
||||||
Task { @MainActor in
|
|
||||||
await action()
|
|
||||||
guard let scrollView else { return }
|
|
||||||
if configuration.hasMore {
|
|
||||||
await scrollView.mj_footer?.endRefreshing()
|
|
||||||
} else {
|
|
||||||
await scrollView.mj_footer?.endRefreshingWithNoMoreData()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// 根据是否还有更多数据更新 footer 状态。
|
|
||||||
private func updateFooterState(hasMore: Bool) {
|
|
||||||
guard let footer = scrollView?.mj_footer else { return }
|
|
||||||
if hasMore {
|
|
||||||
footer.resetNoMoreData()
|
|
||||||
footer.isHidden = false
|
|
||||||
} else {
|
|
||||||
Task { @MainActor in
|
|
||||||
await footer.endRefreshingWithNoMoreData()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// 释放与锚点关联的 MJRefresh 组件。
|
|
||||||
func unbind(from anchorView: UIView) {
|
|
||||||
pendingApply?.cancel()
|
|
||||||
pendingApply = nil
|
|
||||||
guard let scrollView = anchorView.enclosingScrollView, scrollView === self.scrollView else { return }
|
|
||||||
scrollView.mj_header = nil
|
|
||||||
scrollView.mj_footer = nil
|
|
||||||
self.scrollView = nil
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
extension UIView {
|
|
||||||
/// 向上查找最近的 `UIScrollView`,供 SwiftUI 滚动容器桥接 MJRefresh。
|
|
||||||
var enclosingScrollView: UIScrollView? {
|
|
||||||
var current: UIView? = self
|
|
||||||
while let view = current {
|
|
||||||
if let scrollView = view as? UIScrollView {
|
|
||||||
return scrollView
|
|
||||||
}
|
|
||||||
current = view.superview
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -63,7 +63,7 @@ final class CloudStorageViewModel: ObservableObject {
|
|||||||
@Published var searchText = ""
|
@Published var searchText = ""
|
||||||
@Published var selectedFilter: CloudDriveFilter = .all
|
@Published var selectedFilter: CloudDriveFilter = .all
|
||||||
@Published var selectedSort: CloudDriveSort = .updatedDesc
|
@Published var selectedSort: CloudDriveSort = .updatedDesc
|
||||||
@Published var isLoading = false
|
private var isLoading = false
|
||||||
@Published var isLoadingMore = false
|
@Published var isLoadingMore = false
|
||||||
@Published var isMutating = false
|
@Published var isMutating = false
|
||||||
@Published var errorMessage: String?
|
@Published var errorMessage: String?
|
||||||
@ -267,9 +267,9 @@ final class MediaLibraryViewModel: ObservableObject {
|
|||||||
@Published var page = 1
|
@Published var page = 1
|
||||||
@Published var keyword = ""
|
@Published var keyword = ""
|
||||||
@Published var selectedAuditFilter: MediaLibraryAuditFilter = .all
|
@Published var selectedAuditFilter: MediaLibraryAuditFilter = .all
|
||||||
@Published var isLoading = false
|
private var isLoading = false
|
||||||
@Published var isLoadingMore = false
|
@Published var isLoadingMore = false
|
||||||
@Published var isLoadingDetail = false
|
private var isLoadingDetail = false
|
||||||
@Published var errorMessage: String?
|
@Published var errorMessage: String?
|
||||||
|
|
||||||
private let pageSize = 10
|
private let pageSize = 10
|
||||||
@ -614,7 +614,7 @@ final class AlbumListViewModel: ObservableObject {
|
|||||||
@Published var searchText = ""
|
@Published var searchText = ""
|
||||||
@Published var startTime = ""
|
@Published var startTime = ""
|
||||||
@Published var endTime = ""
|
@Published var endTime = ""
|
||||||
@Published var isLoading = false
|
private var isLoading = false
|
||||||
@Published var isLoadingMore = false
|
@Published var isLoadingMore = false
|
||||||
@Published var isMutating = false
|
@Published var isMutating = false
|
||||||
@Published var errorMessage: String?
|
@Published var errorMessage: String?
|
||||||
@ -718,7 +718,7 @@ final class AlbumDetailViewModel: ObservableObject {
|
|||||||
@Published var selectedTab: AlbumFileTab = .image
|
@Published var selectedTab: AlbumFileTab = .image
|
||||||
@Published var total = 0
|
@Published var total = 0
|
||||||
@Published var page = 1
|
@Published var page = 1
|
||||||
@Published var isLoading = false
|
private var isLoading = false
|
||||||
@Published var isLoadingMore = false
|
@Published var isLoadingMore = false
|
||||||
@Published var isMutating = false
|
@Published var isMutating = false
|
||||||
@Published var errorMessage: String?
|
@Published var errorMessage: String?
|
||||||
@ -862,7 +862,7 @@ final class AlbumTrailerViewModel: ObservableObject {
|
|||||||
@Published var selectedFolderId: Int?
|
@Published var selectedFolderId: Int?
|
||||||
@Published var localFiles: [AlbumLocalUploadFile] = []
|
@Published var localFiles: [AlbumLocalUploadFile] = []
|
||||||
@Published var uploadProgress = 0
|
@Published var uploadProgress = 0
|
||||||
@Published var isLoadingFolders = false
|
private var isLoadingFolders = false
|
||||||
@Published var isSubmitting = false
|
@Published var isSubmitting = false
|
||||||
@Published var errorMessage: String?
|
@Published var errorMessage: String?
|
||||||
@Published var didUploadSuccessfully = false
|
@Published var didUploadSuccessfully = false
|
||||||
|
|||||||
@ -135,7 +135,7 @@ final class LocationReportHistoryViewModel: ObservableObject {
|
|||||||
@Published var endDate: Date?
|
@Published var endDate: Date?
|
||||||
@Published var items: [LocationReportHistoryItem] = []
|
@Published var items: [LocationReportHistoryItem] = []
|
||||||
@Published var errorMessage: String?
|
@Published var errorMessage: String?
|
||||||
@Published var isLoading = false
|
private var isLoading = false
|
||||||
@Published var isLoadingMore = false
|
@Published var isLoadingMore = false
|
||||||
@Published var total = 0
|
@Published var total = 0
|
||||||
|
|
||||||
|
|||||||
@ -20,8 +20,8 @@ final class PaymentCollectionViewModel: ObservableObject {
|
|||||||
@Published var remarkText = ""
|
@Published var remarkText = ""
|
||||||
@Published var currentPayUrl = ""
|
@Published var currentPayUrl = ""
|
||||||
@Published var qrImage: UIImage?
|
@Published var qrImage: UIImage?
|
||||||
@Published var isLoading = false
|
private var isLoading = false
|
||||||
@Published var isPolling = false
|
private var isPolling = false
|
||||||
@Published var errorMessage: String?
|
@Published var errorMessage: String?
|
||||||
@Published var status: PaymentCollectionStatus = .idle
|
@Published var status: PaymentCollectionStatus = .idle
|
||||||
|
|
||||||
@ -193,7 +193,7 @@ private extension String {
|
|||||||
/// 收款记录 ViewModel,管理收款记录加载、日期分组和汇总兜底。
|
/// 收款记录 ViewModel,管理收款记录加载、日期分组和汇总兜底。
|
||||||
final class PaymentCollectionRecordViewModel: ObservableObject {
|
final class PaymentCollectionRecordViewModel: ObservableObject {
|
||||||
@Published var groups: [PaymentCollectionRecordGroup] = []
|
@Published var groups: [PaymentCollectionRecordGroup] = []
|
||||||
@Published var isLoading = false
|
private var isLoading = false
|
||||||
@Published var errorMessage: String?
|
@Published var errorMessage: String?
|
||||||
|
|
||||||
/// 加载当前景区收款记录,无景区时不请求接口。
|
/// 加载当前景区收款记录,无景区时不请求接口。
|
||||||
|
|||||||
@ -13,7 +13,7 @@ import Combine
|
|||||||
final class ProfileViewModel: ObservableObject {
|
final class ProfileViewModel: ObservableObject {
|
||||||
@Published var userInfo: UserInfoResponse?
|
@Published var userInfo: UserInfoResponse?
|
||||||
@Published var realNameInfo: RealNameInfo?
|
@Published var realNameInfo: RealNameInfo?
|
||||||
@Published var isLoading = false
|
private var isLoading = false
|
||||||
@Published var isSaving = false
|
@Published var isSaving = false
|
||||||
@Published var isEditingProfile = false
|
@Published var isEditingProfile = false
|
||||||
@Published var editingNickname = ""
|
@Published var editingNickname = ""
|
||||||
|
|||||||
@ -15,7 +15,7 @@ final class PunchPointListViewModel: ObservableObject {
|
|||||||
@Published var items: [PunchPointItem] = []
|
@Published var items: [PunchPointItem] = []
|
||||||
@Published var selectedDetail: PunchPointItem?
|
@Published var selectedDetail: PunchPointItem?
|
||||||
@Published var errorMessage: String?
|
@Published var errorMessage: String?
|
||||||
@Published var isLoading = false
|
private var isLoading = false
|
||||||
@Published var isLoadingMore = false
|
@Published var isLoadingMore = false
|
||||||
@Published var total = 0
|
@Published var total = 0
|
||||||
|
|
||||||
|
|||||||
@ -179,7 +179,7 @@ enum ScenicSettlementAmountValidation: Equatable {
|
|||||||
final class ScenicSettlementReviewViewModel: ObservableObject {
|
final class ScenicSettlementReviewViewModel: ObservableObject {
|
||||||
@Published var scenicApplications: [ScenicApplicationPendingResponse] = []
|
@Published var scenicApplications: [ScenicApplicationPendingResponse] = []
|
||||||
@Published var roleApplications: [RoleApplyPendingResponse] = []
|
@Published var roleApplications: [RoleApplyPendingResponse] = []
|
||||||
@Published var isLoading = false
|
private var isLoading = false
|
||||||
@Published var message: String?
|
@Published var message: String?
|
||||||
@Published var loadFailedAll = false
|
@Published var loadFailedAll = false
|
||||||
@Published var scenicLoadFailed = false
|
@Published var scenicLoadFailed = false
|
||||||
|
|||||||
@ -39,7 +39,7 @@ final class TaskCloudFileSelectionViewModel: ObservableObject {
|
|||||||
@Published var searchText = ""
|
@Published var searchText = ""
|
||||||
@Published var selectedFilter: TaskCloudFileFilter = .all
|
@Published var selectedFilter: TaskCloudFileFilter = .all
|
||||||
@Published var selectedFiles: [CloudDriveFile] = []
|
@Published var selectedFiles: [CloudDriveFile] = []
|
||||||
@Published var isLoading = false
|
private var isLoading = false
|
||||||
@Published var isLoadingMore = false
|
@Published var isLoadingMore = false
|
||||||
@Published var errorMessage: String?
|
@Published var errorMessage: String?
|
||||||
|
|
||||||
|
|||||||
@ -51,7 +51,7 @@ final class TaskCreateViewModel: ObservableObject {
|
|||||||
@Published var availableOrders: [AvailableOrderResponse] = []
|
@Published var availableOrders: [AvailableOrderResponse] = []
|
||||||
@Published var selectedCloudFiles: [TaskCloudSelectionItem] = []
|
@Published var selectedCloudFiles: [TaskCloudSelectionItem] = []
|
||||||
@Published var selectedLocalFiles: [TaskLocalUploadItem] = []
|
@Published var selectedLocalFiles: [TaskLocalUploadItem] = []
|
||||||
@Published var isLoadingOrders = false
|
private(set) var isLoadingOrders = false
|
||||||
@Published var isSubmitting = false
|
@Published var isSubmitting = false
|
||||||
@Published var errorMessage: String?
|
@Published var errorMessage: String?
|
||||||
@Published var didSubmitSuccessfully = false
|
@Published var didSubmitSuccessfully = false
|
||||||
|
|||||||
@ -38,7 +38,7 @@ enum TaskStatusFilter: Int, CaseIterable, Identifiable {
|
|||||||
/// 任务管理 ViewModel,负责任务列表、筛选、分页和错误状态。
|
/// 任务管理 ViewModel,负责任务列表、筛选、分页和错误状态。
|
||||||
@MainActor
|
@MainActor
|
||||||
final class TaskManagementViewModel: ObservableObject {
|
final class TaskManagementViewModel: ObservableObject {
|
||||||
@Published var isLoading = false
|
private var isLoading = false
|
||||||
@Published var isLoadingMore = false
|
@Published var isLoadingMore = false
|
||||||
@Published var tasks: [PhotographerTaskItem] = []
|
@Published var tasks: [PhotographerTaskItem] = []
|
||||||
@Published var total = 0
|
@Published var total = 0
|
||||||
@ -146,7 +146,7 @@ final class TaskManagementViewModel: ObservableObject {
|
|||||||
/// 任务详情 ViewModel,负责详情加载和列表摘要兜底展示。
|
/// 任务详情 ViewModel,负责详情加载和列表摘要兜底展示。
|
||||||
@MainActor
|
@MainActor
|
||||||
final class TaskDetailViewModel: ObservableObject {
|
final class TaskDetailViewModel: ObservableObject {
|
||||||
@Published var isLoading = false
|
private var isLoading = false
|
||||||
@Published var detail: TaskDetailResponse?
|
@Published var detail: TaskDetailResponse?
|
||||||
@Published var errorMessage: String?
|
@Published var errorMessage: String?
|
||||||
|
|
||||||
|
|||||||
@ -229,7 +229,7 @@ final class WithdrawApplyViewModel: ObservableObject {
|
|||||||
@Published var info: WithdrawInfoResponse?
|
@Published var info: WithdrawInfoResponse?
|
||||||
@Published var amountText = ""
|
@Published var amountText = ""
|
||||||
@Published var smsCode = ""
|
@Published var smsCode = ""
|
||||||
@Published var isLoading = false
|
private var isLoading = false
|
||||||
@Published var isSubmitting = false
|
@Published var isSubmitting = false
|
||||||
@Published var smsCountdown = 0
|
@Published var smsCountdown = 0
|
||||||
@Published var errorMessage: String?
|
@Published var errorMessage: String?
|
||||||
@ -309,7 +309,7 @@ final class WithdrawalSettingsViewModel: ObservableObject {
|
|||||||
@Published var frontImageURL = ""
|
@Published var frontImageURL = ""
|
||||||
@Published var backImageURL = ""
|
@Published var backImageURL = ""
|
||||||
@Published var uploadProgress = 0
|
@Published var uploadProgress = 0
|
||||||
@Published var isLoading = false
|
private var isLoading = false
|
||||||
@Published var isSubmitting = false
|
@Published var isSubmitting = false
|
||||||
@Published var smsCountdown = 0
|
@Published var smsCountdown = 0
|
||||||
@Published var errorMessage: String?
|
@Published var errorMessage: String?
|
||||||
@ -442,7 +442,7 @@ final class PointsRedemptionViewModel: ObservableObject {
|
|||||||
@Published var overview = PointOverviewResponse()
|
@Published var overview = PointOverviewResponse()
|
||||||
@Published var records: [PointWithdrawItem] = []
|
@Published var records: [PointWithdrawItem] = []
|
||||||
@Published var pointsText = ""
|
@Published var pointsText = ""
|
||||||
@Published var isLoading = false
|
private var isLoading = false
|
||||||
@Published var isSubmitting = false
|
@Published var isSubmitting = false
|
||||||
@Published var errorMessage: String?
|
@Published var errorMessage: String?
|
||||||
|
|
||||||
|
|||||||
@ -1,38 +0,0 @@
|
|||||||
//
|
|
||||||
// MJRefreshSupportTests.swift
|
|
||||||
// suixinkanTests
|
|
||||||
//
|
|
||||||
// Created by Codex on 2026/6/26.
|
|
||||||
//
|
|
||||||
|
|
||||||
import XCTest
|
|
||||||
@testable import suixinkan
|
|
||||||
|
|
||||||
/// MJRefresh SwiftUI 桥接测试,覆盖滚动视图查找辅助逻辑。
|
|
||||||
final class MJRefreshSupportTests: XCTestCase {
|
|
||||||
/// 测试锚点视图能向上找到最近的 UIScrollView。
|
|
||||||
func testEnclosingScrollViewFindsParentScrollView() {
|
|
||||||
let scrollView = UIScrollView(frame: CGRect(x: 0, y: 0, width: 320, height: 480))
|
|
||||||
let container = UIView(frame: scrollView.bounds)
|
|
||||||
let anchor = UIView(frame: .zero)
|
|
||||||
scrollView.addSubview(container)
|
|
||||||
container.addSubview(anchor)
|
|
||||||
|
|
||||||
XCTAssertIdentical(anchor.enclosingScrollView, scrollView)
|
|
||||||
}
|
|
||||||
|
|
||||||
/// 测试没有父级 ScrollView 时返回 nil。
|
|
||||||
func testEnclosingScrollViewReturnsNilWithoutScrollView() {
|
|
||||||
let view = UIView(frame: .zero)
|
|
||||||
XCTAssertNil(view.enclosingScrollView)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
extension MJRefreshSupportTests {
|
|
||||||
/// 断言两个对象引用相同。
|
|
||||||
fileprivate func XCTAssertIdentical(_ expression1: AnyObject?, _ expression2: AnyObject?, file: StaticString = #filePath, line: UInt = #line) {
|
|
||||||
if expression1 !== expression2 {
|
|
||||||
XCTFail("Expected identical objects", file: file, line: line)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Reference in New Issue
Block a user