提交
This commit is contained in:
19
Pods/MJRefresh/LICENSE
generated
Executable file
19
Pods/MJRefresh/LICENSE
generated
Executable file
@@ -0,0 +1,19 @@
|
||||
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
Executable file
34
Pods/MJRefresh/MJRefresh/Base/MJRefreshAutoFooter.h
generated
Executable file
@@ -0,0 +1,34 @@
|
||||
//
|
||||
// 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
Executable file
216
Pods/MJRefresh/MJRefresh/Base/MJRefreshAutoFooter.m
generated
Executable file
@@ -0,0 +1,216 @@
|
||||
//
|
||||
// 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;
|
||||
} 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;
|
||||
}
|
||||
}
|
||||
|
||||
- (void)setAutoTriggerTimes:(NSInteger)autoTriggerTimes {
|
||||
_autoTriggerTimes = autoTriggerTimes;
|
||||
self.leftTriggerTimes = autoTriggerTimes;
|
||||
}
|
||||
@end
|
||||
21
Pods/MJRefresh/MJRefresh/Base/MJRefreshBackFooter.h
generated
Executable file
21
Pods/MJRefresh/MJRefresh/Base/MJRefreshBackFooter.h
generated
Executable file
@@ -0,0 +1,21 @@
|
||||
//
|
||||
// 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
Executable file
158
Pods/MJRefresh/MJRefresh/Base/MJRefreshBackFooter.m
generated
Executable file
@@ -0,0 +1,158 @@
|
||||
//
|
||||
// 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
Executable file
151
Pods/MJRefresh/MJRefresh/Base/MJRefreshComponent.h
generated
Executable file
@@ -0,0 +1,151 @@
|
||||
// 代码地址: 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
Executable file
323
Pods/MJRefresh/MJRefresh/Base/MJRefreshComponent.m
generated
Executable file
@@ -0,0 +1,323 @@
|
||||
// 代码地址: 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
Executable file
37
Pods/MJRefresh/MJRefresh/Base/MJRefreshFooter.h
generated
Executable file
@@ -0,0 +1,37 @@
|
||||
// 代码地址: 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
Executable file
71
Pods/MJRefresh/MJRefresh/Base/MJRefreshFooter.m
generated
Executable file
@@ -0,0 +1,71 @@
|
||||
// 代码地址: 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
Executable file
35
Pods/MJRefresh/MJRefresh/Base/MJRefreshHeader.h
generated
Executable file
@@ -0,0 +1,35 @@
|
||||
// 代码地址: 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
Executable file
297
Pods/MJRefresh/MJRefresh/Base/MJRefreshHeader.m
generated
Executable file
@@ -0,0 +1,297 @@
|
||||
// 代码地址: 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 (self.scrollView.mj_insetT != insetT) {
|
||||
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
Executable file
30
Pods/MJRefresh/MJRefresh/Base/MJRefreshTrailer.h
generated
Executable file
@@ -0,0 +1,30 @@
|
||||
//
|
||||
// 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
Executable file
179
Pods/MJRefresh/MJRefresh/Base/MJRefreshTrailer.m
generated
Executable file
@@ -0,0 +1,179 @@
|
||||
//
|
||||
// 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
|
||||
25
Pods/MJRefresh/MJRefresh/Custom/Footer/Auto/MJRefreshAutoGifFooter.h
generated
Executable file
25
Pods/MJRefresh/MJRefresh/Custom/Footer/Auto/MJRefreshAutoGifFooter.h
generated
Executable file
@@ -0,0 +1,25 @@
|
||||
//
|
||||
// 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
|
||||
121
Pods/MJRefresh/MJRefresh/Custom/Footer/Auto/MJRefreshAutoGifFooter.m
generated
Executable file
121
Pods/MJRefresh/MJRefresh/Custom/Footer/Auto/MJRefreshAutoGifFooter.m
generated
Executable file
@@ -0,0 +1,121 @@
|
||||
//
|
||||
// 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
|
||||
|
||||
25
Pods/MJRefresh/MJRefresh/Custom/Footer/Auto/MJRefreshAutoNormalFooter.h
generated
Executable file
25
Pods/MJRefresh/MJRefresh/Custom/Footer/Auto/MJRefreshAutoNormalFooter.h
generated
Executable file
@@ -0,0 +1,25 @@
|
||||
//
|
||||
// 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
|
||||
81
Pods/MJRefresh/MJRefresh/Custom/Footer/Auto/MJRefreshAutoNormalFooter.m
generated
Executable file
81
Pods/MJRefresh/MJRefresh/Custom/Footer/Auto/MJRefreshAutoNormalFooter.m
generated
Executable file
@@ -0,0 +1,81 @@
|
||||
//
|
||||
// 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
|
||||
30
Pods/MJRefresh/MJRefresh/Custom/Footer/Auto/MJRefreshAutoStateFooter.h
generated
Executable file
30
Pods/MJRefresh/MJRefresh/Custom/Footer/Auto/MJRefreshAutoStateFooter.h
generated
Executable file
@@ -0,0 +1,30 @@
|
||||
//
|
||||
// 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
|
||||
119
Pods/MJRefresh/MJRefresh/Custom/Footer/Auto/MJRefreshAutoStateFooter.m
generated
Executable file
119
Pods/MJRefresh/MJRefresh/Custom/Footer/Auto/MJRefreshAutoStateFooter.m
generated
Executable file
@@ -0,0 +1,119 @@
|
||||
//
|
||||
// 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
|
||||
25
Pods/MJRefresh/MJRefresh/Custom/Footer/Back/MJRefreshBackGifFooter.h
generated
Executable file
25
Pods/MJRefresh/MJRefresh/Custom/Footer/Back/MJRefreshBackGifFooter.h
generated
Executable file
@@ -0,0 +1,25 @@
|
||||
//
|
||||
// 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
|
||||
132
Pods/MJRefresh/MJRefresh/Custom/Footer/Back/MJRefreshBackGifFooter.m
generated
Executable file
132
Pods/MJRefresh/MJRefresh/Custom/Footer/Back/MJRefreshBackGifFooter.m
generated
Executable file
@@ -0,0 +1,132 @@
|
||||
//
|
||||
// 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
|
||||
25
Pods/MJRefresh/MJRefresh/Custom/Footer/Back/MJRefreshBackNormalFooter.h
generated
Executable file
25
Pods/MJRefresh/MJRefresh/Custom/Footer/Back/MJRefreshBackNormalFooter.h
generated
Executable file
@@ -0,0 +1,25 @@
|
||||
//
|
||||
// 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
|
||||
132
Pods/MJRefresh/MJRefresh/Custom/Footer/Back/MJRefreshBackNormalFooter.m
generated
Executable file
132
Pods/MJRefresh/MJRefresh/Custom/Footer/Back/MJRefreshBackNormalFooter.m
generated
Executable file
@@ -0,0 +1,132 @@
|
||||
//
|
||||
// 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
|
||||
29
Pods/MJRefresh/MJRefresh/Custom/Footer/Back/MJRefreshBackStateFooter.h
generated
Executable file
29
Pods/MJRefresh/MJRefresh/Custom/Footer/Back/MJRefreshBackStateFooter.h
generated
Executable file
@@ -0,0 +1,29 @@
|
||||
//
|
||||
// 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
|
||||
93
Pods/MJRefresh/MJRefresh/Custom/Footer/Back/MJRefreshBackStateFooter.m
generated
Executable file
93
Pods/MJRefresh/MJRefresh/Custom/Footer/Back/MJRefreshBackStateFooter.m
generated
Executable file
@@ -0,0 +1,93 @@
|
||||
//
|
||||
// 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
|
||||
25
Pods/MJRefresh/MJRefresh/Custom/Header/MJRefreshGifHeader.h
generated
Executable file
25
Pods/MJRefresh/MJRefresh/Custom/Header/MJRefreshGifHeader.h
generated
Executable file
@@ -0,0 +1,25 @@
|
||||
//
|
||||
// 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
|
||||
135
Pods/MJRefresh/MJRefresh/Custom/Header/MJRefreshGifHeader.m
generated
Executable file
135
Pods/MJRefresh/MJRefresh/Custom/Header/MJRefreshGifHeader.m
generated
Executable file
@@ -0,0 +1,135 @@
|
||||
//
|
||||
// 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
|
||||
26
Pods/MJRefresh/MJRefresh/Custom/Header/MJRefreshNormalHeader.h
generated
Executable file
26
Pods/MJRefresh/MJRefresh/Custom/Header/MJRefreshNormalHeader.h
generated
Executable file
@@ -0,0 +1,26 @@
|
||||
//
|
||||
// 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
|
||||
137
Pods/MJRefresh/MJRefresh/Custom/Header/MJRefreshNormalHeader.m
generated
Executable file
137
Pods/MJRefresh/MJRefresh/Custom/Header/MJRefreshNormalHeader.m
generated
Executable file
@@ -0,0 +1,137 @@
|
||||
//
|
||||
// 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
|
||||
39
Pods/MJRefresh/MJRefresh/Custom/Header/MJRefreshStateHeader.h
generated
Executable file
39
Pods/MJRefresh/MJRefresh/Custom/Header/MJRefreshStateHeader.h
generated
Executable file
@@ -0,0 +1,39 @@
|
||||
//
|
||||
// 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
|
||||
191
Pods/MJRefresh/MJRefresh/Custom/Header/MJRefreshStateHeader.m
generated
Executable file
191
Pods/MJRefresh/MJRefresh/Custom/Header/MJRefreshStateHeader.m
generated
Executable file
@@ -0,0 +1,191 @@
|
||||
//
|
||||
// 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
|
||||
23
Pods/MJRefresh/MJRefresh/Custom/Trailer/MJRefreshNormalTrailer.h
generated
Executable file
23
Pods/MJRefresh/MJRefresh/Custom/Trailer/MJRefreshNormalTrailer.h
generated
Executable file
@@ -0,0 +1,23 @@
|
||||
//
|
||||
// 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
|
||||
80
Pods/MJRefresh/MJRefresh/Custom/Trailer/MJRefreshNormalTrailer.m
generated
Executable file
80
Pods/MJRefresh/MJRefresh/Custom/Trailer/MJRefreshNormalTrailer.m
generated
Executable file
@@ -0,0 +1,80 @@
|
||||
//
|
||||
// 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
|
||||
28
Pods/MJRefresh/MJRefresh/Custom/Trailer/MJRefreshStateTrailer.h
generated
Executable file
28
Pods/MJRefresh/MJRefresh/Custom/Trailer/MJRefreshStateTrailer.h
generated
Executable file
@@ -0,0 +1,28 @@
|
||||
//
|
||||
// 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
|
||||
87
Pods/MJRefresh/MJRefresh/Custom/Trailer/MJRefreshStateTrailer.m
generated
Executable file
87
Pods/MJRefresh/MJRefresh/Custom/Trailer/MJRefreshStateTrailer.m
generated
Executable file
@@ -0,0 +1,87 @@
|
||||
//
|
||||
// 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
Executable file
BIN
Pods/MJRefresh/MJRefresh/MJRefresh.bundle/arrow@2x.png
generated
Executable file
Binary file not shown.
|
After Width: | Height: | Size: 1.0 KiB |
BIN
Pods/MJRefresh/MJRefresh/MJRefresh.bundle/en.lproj/Localizable.strings
generated
Executable file
BIN
Pods/MJRefresh/MJRefresh/MJRefresh.bundle/en.lproj/Localizable.strings
generated
Executable file
Binary file not shown.
16
Pods/MJRefresh/MJRefresh/MJRefresh.bundle/ko.lproj/Localizable.strings
generated
Executable file
16
Pods/MJRefresh/MJRefresh/MJRefresh.bundle/ko.lproj/Localizable.strings
generated
Executable file
@@ -0,0 +1,16 @@
|
||||
"MJRefreshHeaderIdleText" = "아래로 당겨 새로고침";
|
||||
"MJRefreshHeaderPullingText" = "놓으면 새로고침";
|
||||
"MJRefreshHeaderRefreshingText" = "로딩중...";
|
||||
|
||||
"MJRefreshAutoFooterIdleText" = "탭 또는 위로 당겨 로드함";
|
||||
"MJRefreshAutoFooterRefreshingText" = "로딩중...";
|
||||
"MJRefreshAutoFooterNoMoreDataText" = "더이상 데이터 없음";
|
||||
|
||||
"MJRefreshBackFooterIdleText" = "위로 당겨 더 로드 가능";
|
||||
"MJRefreshBackFooterPullingText" = "놓으면 더 로드됨.";
|
||||
"MJRefreshBackFooterRefreshingText" = "로딩중...";
|
||||
"MJRefreshBackFooterNoMoreDataText" = "더이상 데이터 없음";
|
||||
|
||||
"MJRefreshHeaderLastTimeText" = "마지막 업데이트: ";
|
||||
"MJRefreshHeaderDateTodayText" = "오늘";
|
||||
"MJRefreshHeaderNoneLastDateText" = "기록 없음";
|
||||
BIN
Pods/MJRefresh/MJRefresh/MJRefresh.bundle/ru.lproj/Localizable.strings
generated
Executable file
BIN
Pods/MJRefresh/MJRefresh/MJRefresh.bundle/ru.lproj/Localizable.strings
generated
Executable file
Binary file not shown.
BIN
Pods/MJRefresh/MJRefresh/MJRefresh.bundle/trail_arrow@2x.png
generated
Executable file
BIN
Pods/MJRefresh/MJRefresh/MJRefresh.bundle/trail_arrow@2x.png
generated
Executable file
Binary file not shown.
|
After Width: | Height: | Size: 2.3 KiB |
BIN
Pods/MJRefresh/MJRefresh/MJRefresh.bundle/uk.lproj/Localizable.strings
generated
Executable file
BIN
Pods/MJRefresh/MJRefresh/MJRefresh.bundle/uk.lproj/Localizable.strings
generated
Executable file
Binary file not shown.
BIN
Pods/MJRefresh/MJRefresh/MJRefresh.bundle/zh-Hans.lproj/Localizable.strings
generated
Executable file
BIN
Pods/MJRefresh/MJRefresh/MJRefresh.bundle/zh-Hans.lproj/Localizable.strings
generated
Executable file
Binary file not shown.
19
Pods/MJRefresh/MJRefresh/MJRefresh.bundle/zh-Hant.lproj/Localizable.strings
generated
Executable file
19
Pods/MJRefresh/MJRefresh/MJRefresh.bundle/zh-Hant.lproj/Localizable.strings
generated
Executable file
@@ -0,0 +1,19 @@
|
||||
"MJRefreshHeaderIdleText" = "下拉可以刷新";
|
||||
"MJRefreshHeaderPullingText" = "鬆開立即刷新";
|
||||
"MJRefreshHeaderRefreshingText" = "正在刷新數據中...";
|
||||
|
||||
"MJRefreshTrailerIdleText" = "滑動查看圖文詳情";
|
||||
"MJRefreshTrailerPullingText" = "釋放查看圖文詳情";
|
||||
|
||||
"MJRefreshAutoFooterIdleText" = "點擊或上拉加載更多";
|
||||
"MJRefreshAutoFooterRefreshingText" = "正在加載更多的數據...";
|
||||
"MJRefreshAutoFooterNoMoreDataText" = "已經全部加載完畢";
|
||||
|
||||
"MJRefreshBackFooterIdleText" = "上拉可以加載更多";
|
||||
"MJRefreshBackFooterPullingText" = "鬆開立即加載更多";
|
||||
"MJRefreshBackFooterRefreshingText" = "正在加載更多的數據...";
|
||||
"MJRefreshBackFooterNoMoreDataText" = "已經全部加載完畢";
|
||||
|
||||
"MJRefreshHeaderLastTimeText" = "最後更新:";
|
||||
"MJRefreshHeaderDateTodayText" = "今天";
|
||||
"MJRefreshHeaderNoneLastDateText" = "無記錄";
|
||||
42
Pods/MJRefresh/MJRefresh/MJRefresh.h
generated
Executable file
42
Pods/MJRefresh/MJRefresh/MJRefresh.h
generated
Executable file
@@ -0,0 +1,42 @@
|
||||
// 代码地址: 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
Executable file
36
Pods/MJRefresh/MJRefresh/MJRefreshConfig.h
generated
Executable file
@@ -0,0 +1,36 @@
|
||||
//
|
||||
// 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
Executable file
42
Pods/MJRefresh/MJRefresh/MJRefreshConfig.m
generated
Executable file
@@ -0,0 +1,42 @@
|
||||
//
|
||||
// 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
Executable file
115
Pods/MJRefresh/MJRefresh/MJRefreshConst.h
generated
Executable file
@@ -0,0 +1,115 @@
|
||||
// 代码地址: 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
Executable file
39
Pods/MJRefresh/MJRefresh/MJRefreshConst.m
generated
Executable file
@@ -0,0 +1,39 @@
|
||||
// 代码地址: 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
Executable file
21
Pods/MJRefresh/MJRefresh/NSBundle+MJRefresh.h
generated
Executable file
@@ -0,0 +1,21 @@
|
||||
//
|
||||
// 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
Executable file
116
Pods/MJRefresh/MJRefresh/NSBundle+MJRefresh.m
generated
Executable file
@@ -0,0 +1,116 @@
|
||||
//
|
||||
// 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
|
||||
20
Pods/MJRefresh/MJRefresh/UICollectionViewLayout+MJRefresh.h
generated
Executable file
20
Pods/MJRefresh/MJRefresh/UICollectionViewLayout+MJRefresh.h
generated
Executable file
@@ -0,0 +1,20 @@
|
||||
//
|
||||
// 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
|
||||
45
Pods/MJRefresh/MJRefresh/UICollectionViewLayout+MJRefresh.m
generated
Executable file
45
Pods/MJRefresh/MJRefresh/UICollectionViewLayout+MJRefresh.m
generated
Executable file
@@ -0,0 +1,45 @@
|
||||
//
|
||||
// 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
Executable file
28
Pods/MJRefresh/MJRefresh/UIScrollView+MJExtension.h
generated
Executable file
@@ -0,0 +1,28 @@
|
||||
// 代码地址: 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
Executable file
153
Pods/MJRefresh/MJRefresh/UIScrollView+MJExtension.m
generated
Executable file
@@ -0,0 +1,153 @@
|
||||
// 代码地址: 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
Executable file
36
Pods/MJRefresh/MJRefresh/UIScrollView+MJRefresh.h
generated
Executable file
@@ -0,0 +1,36 @@
|
||||
// 代码地址: 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
Executable file
120
Pods/MJRefresh/MJRefresh/UIScrollView+MJRefresh.m
generated
Executable file
@@ -0,0 +1,120 @@
|
||||
// 代码地址: 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
Executable file
22
Pods/MJRefresh/MJRefresh/UIView+MJExtension.h
generated
Executable file
@@ -0,0 +1,22 @@
|
||||
// 代码地址: 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
Executable file
83
Pods/MJRefresh/MJRefresh/UIView+MJExtension.m
generated
Executable file
@@ -0,0 +1,83 @@
|
||||
// 代码地址: 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
Executable file
457
Pods/MJRefresh/README.md
generated
Executable file
@@ -0,0 +1,457 @@
|
||||
## 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
|
||||
Reference in New Issue
Block a user