Initial commit
This commit is contained in:
Generated
+19
@@ -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.
|
||||
+23
@@ -0,0 +1,23 @@
|
||||
//
|
||||
// MJRefreshAutoFooter.h
|
||||
// MJRefreshExample
|
||||
//
|
||||
// Created by MJ Lee on 15/4/24.
|
||||
// Copyright (c) 2015年 小码哥. All rights reserved.
|
||||
//
|
||||
|
||||
#import "MJRefreshFooter.h"
|
||||
|
||||
@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;
|
||||
|
||||
/** 是否每一次拖拽只发一次请求 */
|
||||
@property (assign, nonatomic, getter=isOnlyRefreshPerDrag) BOOL onlyRefreshPerDrag;
|
||||
@end
|
||||
+154
@@ -0,0 +1,154 @@
|
||||
//
|
||||
// MJRefreshAutoFooter.m
|
||||
// MJRefreshExample
|
||||
//
|
||||
// Created by MJ Lee on 15/4/24.
|
||||
// Copyright (c) 2015年 小码哥. All rights reserved.
|
||||
//
|
||||
|
||||
#import "MJRefreshAutoFooter.h"
|
||||
|
||||
@interface MJRefreshAutoFooter()
|
||||
/** 一个新的拖拽 */
|
||||
@property (assign, nonatomic, getter=isOneNewPan) BOOL oneNewPan;
|
||||
@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;
|
||||
|
||||
// 默认是当offset达到条件就发送请求(可连续)
|
||||
self.onlyRefreshPerDrag = NO;
|
||||
}
|
||||
|
||||
- (void)scrollViewContentSizeDidChange:(NSDictionary *)change
|
||||
{
|
||||
[super scrollViewContentSizeDidChange:change];
|
||||
|
||||
// 设置位置
|
||||
self.mj_y = self.scrollView.mj_contentH;
|
||||
}
|
||||
|
||||
- (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;
|
||||
|
||||
// 当底部刷新控件完全出现时,才刷新
|
||||
[self beginRefreshing];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
- (void)scrollViewPanStateDidChange:(NSDictionary *)change
|
||||
{
|
||||
[super scrollViewPanStateDidChange:change];
|
||||
|
||||
if (self.state != MJRefreshStateIdle) return;
|
||||
|
||||
UIGestureRecognizerState panState = _scrollView.panGestureRecognizer.state;
|
||||
if (panState == UIGestureRecognizerStateEnded) {// 手松开
|
||||
if (_scrollView.mj_insetT + _scrollView.mj_contentH <= _scrollView.mj_h) { // 不够一个屏幕
|
||||
if (_scrollView.mj_offsetY >= - _scrollView.mj_insetT) { // 向上拽
|
||||
[self beginRefreshing];
|
||||
}
|
||||
} else { // 超出一个屏幕
|
||||
if (_scrollView.mj_offsetY >= _scrollView.mj_contentH + _scrollView.mj_insetB - _scrollView.mj_h) {
|
||||
[self beginRefreshing];
|
||||
}
|
||||
}
|
||||
} else if (panState == UIGestureRecognizerStateBegan) {
|
||||
self.oneNewPan = YES;
|
||||
}
|
||||
}
|
||||
|
||||
- (void)beginRefreshing
|
||||
{
|
||||
if (!self.isOneNewPan && self.isOnlyRefreshPerDrag) return;
|
||||
|
||||
[super beginRefreshing];
|
||||
|
||||
self.oneNewPan = NO;
|
||||
}
|
||||
|
||||
- (void)setState:(MJRefreshState)state
|
||||
{
|
||||
MJRefreshCheckState
|
||||
|
||||
if (state == MJRefreshStateRefreshing) {
|
||||
[self executeRefreshingCallback];
|
||||
} else if (state == MJRefreshStateNoMoreData || state == MJRefreshStateIdle) {
|
||||
if (MJRefreshStateRefreshing == oldState) {
|
||||
if (self.endRefreshingCompletionBlock) {
|
||||
self.endRefreshingCompletionBlock();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
- (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;
|
||||
}
|
||||
}
|
||||
@end
|
||||
+13
@@ -0,0 +1,13 @@
|
||||
//
|
||||
// MJRefreshBackFooter.h
|
||||
// MJRefreshExample
|
||||
//
|
||||
// Created by MJ Lee on 15/4/24.
|
||||
// Copyright (c) 2015年 小码哥. All rights reserved.
|
||||
//
|
||||
|
||||
#import "MJRefreshFooter.h"
|
||||
|
||||
@interface MJRefreshBackFooter : MJRefreshFooter
|
||||
|
||||
@end
|
||||
+146
@@ -0,0 +1,146 @@
|
||||
//
|
||||
// MJRefreshBackFooter.m
|
||||
// MJRefreshExample
|
||||
//
|
||||
// Created by MJ Lee on 15/4/24.
|
||||
// Copyright (c) 2015年 小码哥. All rights reserved.
|
||||
//
|
||||
|
||||
#import "MJRefreshBackFooter.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];
|
||||
|
||||
// 内容的高度
|
||||
CGFloat contentHeight = self.scrollView.mj_contentH + self.ignoredScrollViewContentInsetBottom;
|
||||
// 表格的高度
|
||||
CGFloat scrollHeight = self.scrollView.mj_h - self.scrollViewOriginalInset.top - self.scrollViewOriginalInset.bottom + self.ignoredScrollViewContentInsetBottom;
|
||||
// 设置位置和尺寸
|
||||
self.mj_y = MAX(contentHeight, scrollHeight);
|
||||
}
|
||||
|
||||
- (void)setState:(MJRefreshState)state
|
||||
{
|
||||
MJRefreshCheckState
|
||||
|
||||
// 根据状态来设置属性
|
||||
if (state == MJRefreshStateNoMoreData || state == MJRefreshStateIdle) {
|
||||
// 刷新完毕
|
||||
if (MJRefreshStateRefreshing == oldState) {
|
||||
[UIView animateWithDuration:MJRefreshSlowAnimationDuration animations:^{
|
||||
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:MJRefreshFastAnimationDuration 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
|
||||
+107
@@ -0,0 +1,107 @@
|
||||
// 代码地址: https://github.com/CoderMJLee/MJRefresh
|
||||
// 代码地址: http://code4app.com/ios/%E5%BF%AB%E9%80%9F%E9%9B%86%E6%88%90%E4%B8%8B%E6%8B%89%E4%B8%8A%E6%8B%89%E5%88%B7%E6%96%B0/52326ce26803fabc46000000
|
||||
// MJRefreshComponent.h
|
||||
// MJRefreshExample
|
||||
//
|
||||
// Created by MJ Lee on 15/3/4.
|
||||
// Copyright (c) 2015年 小码哥. All rights reserved.
|
||||
// 刷新控件的基类
|
||||
|
||||
#import <UIKit/UIKit.h>
|
||||
#import "MJRefreshConst.h"
|
||||
#import "UIView+MJExtension.h"
|
||||
#import "UIScrollView+MJExtension.h"
|
||||
#import "UIScrollView+MJRefresh.h"
|
||||
#import "NSBundle+MJRefresh.h"
|
||||
|
||||
/** 刷新控件的状态 */
|
||||
typedef NS_ENUM(NSInteger, MJRefreshState) {
|
||||
/** 普通闲置状态 */
|
||||
MJRefreshStateIdle = 1,
|
||||
/** 松开就可以进行刷新的状态 */
|
||||
MJRefreshStatePulling,
|
||||
/** 正在刷新中的状态 */
|
||||
MJRefreshStateRefreshing,
|
||||
/** 即将刷新的状态 */
|
||||
MJRefreshStateWillRefresh,
|
||||
/** 所有数据加载完毕,没有更多的数据了 */
|
||||
MJRefreshStateNoMoreData
|
||||
};
|
||||
|
||||
/** 进入刷新状态的回调 */
|
||||
typedef void (^MJRefreshComponentRefreshingBlock)(void);
|
||||
/** 开始刷新后的回调(进入刷新状态后的回调) */
|
||||
typedef void (^MJRefreshComponentbeginRefreshingCompletionBlock)(void);
|
||||
/** 结束刷新后的回调 */
|
||||
typedef void (^MJRefreshComponentEndRefreshingCompletionBlock)(void);
|
||||
|
||||
/** 刷新控件的基类 */
|
||||
@interface MJRefreshComponent : UIView
|
||||
{
|
||||
/** 记录scrollView刚开始的inset */
|
||||
UIEdgeInsets _scrollViewOriginalInset;
|
||||
/** 父控件 */
|
||||
__weak UIScrollView *_scrollView;
|
||||
}
|
||||
#pragma mark - 刷新回调
|
||||
/** 正在刷新的回调 */
|
||||
@property (copy, nonatomic) MJRefreshComponentRefreshingBlock 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) MJRefreshComponentbeginRefreshingCompletionBlock beginRefreshingCompletionBlock;
|
||||
/** 结束刷新的回调 */
|
||||
@property (copy, nonatomic) MJRefreshComponentEndRefreshingCompletionBlock endRefreshingCompletionBlock;
|
||||
/** 结束刷新状态 */
|
||||
- (void)endRefreshing;
|
||||
- (void)endRefreshingWithCompletionBlock:(void (^)(void))completionBlock;
|
||||
/** 是否正在刷新 */
|
||||
@property (assign, nonatomic, readonly, getter=isRefreshing) BOOL refreshing;
|
||||
//- (BOOL)isRefreshing;
|
||||
/** 刷新状态 一般交给子类内部实现 */
|
||||
@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:(NSDictionary *)change NS_REQUIRES_SUPER;
|
||||
/** 当scrollView的contentSize发生改变的时候调用 */
|
||||
- (void)scrollViewContentSizeDidChange:(NSDictionary *)change NS_REQUIRES_SUPER;
|
||||
/** 当scrollView的拖拽状态发生改变的时候调用 */
|
||||
- (void)scrollViewPanStateDidChange:(NSDictionary *)change 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_textWith;
|
||||
@end
|
||||
+272
@@ -0,0 +1,272 @@
|
||||
// 代码地址: https://github.com/CoderMJLee/MJRefresh
|
||||
// 代码地址: http://code4app.com/ios/%E5%BF%AB%E9%80%9F%E9%9B%86%E6%88%90%E4%B8%8B%E6%8B%89%E4%B8%8A%E6%8B%89%E5%88%B7%E6%96%B0/52326ce26803fabc46000000
|
||||
// MJRefreshComponent.m
|
||||
// MJRefreshExample
|
||||
//
|
||||
// Created by MJ Lee on 15/3/4.
|
||||
// Copyright (c) 2015年 小码哥. All rights reserved.
|
||||
//
|
||||
|
||||
#import "MJRefreshComponent.h"
|
||||
#import "MJRefreshConst.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;
|
||||
}
|
||||
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) { // 新的父控件
|
||||
// 设置宽度
|
||||
self.mj_w = newSuperview.mj_w;
|
||||
// 设置位置
|
||||
self.mj_x = -_scrollView.mj_insetL;
|
||||
|
||||
// 记录UIScrollView
|
||||
_scrollView = (UIScrollView *)newSuperview;
|
||||
// 设置永远支持垂直弹簧效果
|
||||
_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];
|
||||
}
|
||||
|
||||
- (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{}
|
||||
|
||||
#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:MJRefreshFastAnimationDuration 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
|
||||
{
|
||||
MJRefreshDispatchAsyncOnMainQueue({
|
||||
if (self.refreshingBlock) {
|
||||
self.refreshingBlock();
|
||||
}
|
||||
if ([self.refreshingTarget respondsToSelector:self.refreshingAction]) {
|
||||
MJRefreshMsgSend(MJRefreshMsgTarget(self.refreshingTarget), self.refreshingAction, self);
|
||||
}
|
||||
if (self.beginRefreshingCompletionBlock) {
|
||||
self.beginRefreshingCompletionBlock();
|
||||
}
|
||||
})
|
||||
}
|
||||
@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_textWith {
|
||||
CGFloat stringWidth = 0;
|
||||
CGSize size = CGSizeMake(MAXFLOAT, MAXFLOAT);
|
||||
if (self.text.length > 0) {
|
||||
#if defined(__IPHONE_OS_VERSION_MAX_ALLOWED) && __IPHONE_OS_VERSION_MAX_ALLOWED >= 70000
|
||||
stringWidth =[self.text
|
||||
boundingRectWithSize:size
|
||||
options:NSStringDrawingUsesLineFragmentOrigin
|
||||
attributes:@{NSFontAttributeName:self.font}
|
||||
context:nil].size.width;
|
||||
#else
|
||||
|
||||
stringWidth = [self.text sizeWithFont:self.font
|
||||
constrainedToSize:size
|
||||
lineBreakMode:NSLineBreakByCharWrapping].width;
|
||||
#endif
|
||||
}
|
||||
return stringWidth;
|
||||
}
|
||||
@end
|
||||
+30
@@ -0,0 +1,30 @@
|
||||
// 代码地址: https://github.com/CoderMJLee/MJRefresh
|
||||
// 代码地址: http://code4app.com/ios/%E5%BF%AB%E9%80%9F%E9%9B%86%E6%88%90%E4%B8%8B%E6%8B%89%E4%B8%8A%E6%8B%89%E5%88%B7%E6%96%B0/52326ce26803fabc46000000
|
||||
// MJRefreshFooter.h
|
||||
// MJRefreshExample
|
||||
//
|
||||
// Created by MJ Lee on 15/3/5.
|
||||
// Copyright (c) 2015年 小码哥. All rights reserved.
|
||||
// 上拉刷新控件
|
||||
|
||||
#import "MJRefreshComponent.h"
|
||||
|
||||
@interface MJRefreshFooter : MJRefreshComponent
|
||||
/** 创建footer */
|
||||
+ (instancetype)footerWithRefreshingBlock:(MJRefreshComponentRefreshingBlock)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
|
||||
+80
@@ -0,0 +1,80 @@
|
||||
// 代码地址: https://github.com/CoderMJLee/MJRefresh
|
||||
// 代码地址: http://code4app.com/ios/%E5%BF%AB%E9%80%9F%E9%9B%86%E6%88%90%E4%B8%8B%E6%8B%89%E4%B8%8A%E6%8B%89%E5%88%B7%E6%96%B0/52326ce26803fabc46000000
|
||||
// MJRefreshFooter.m
|
||||
// MJRefreshExample
|
||||
//
|
||||
// Created by MJ Lee on 15/3/5.
|
||||
// Copyright (c) 2015年 小码哥. All rights reserved.
|
||||
//
|
||||
|
||||
#import "MJRefreshFooter.h"
|
||||
#include "UIScrollView+MJRefresh.h"
|
||||
|
||||
@interface MJRefreshFooter()
|
||||
|
||||
@end
|
||||
|
||||
@implementation MJRefreshFooter
|
||||
#pragma mark - 构造方法
|
||||
+ (instancetype)footerWithRefreshingBlock:(MJRefreshComponentRefreshingBlock)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;
|
||||
}
|
||||
|
||||
- (void)willMoveToSuperview:(UIView *)newSuperview
|
||||
{
|
||||
[super willMoveToSuperview:newSuperview];
|
||||
|
||||
if (newSuperview) {
|
||||
// 监听scrollView数据的变化
|
||||
if ([self.scrollView isKindOfClass:[UITableView class]] || [self.scrollView isKindOfClass:[UICollectionView class]]) {
|
||||
[self.scrollView setMj_reloadDataBlock:^(NSInteger totalDataCount) {
|
||||
if (self.isAutomaticallyHidden) {
|
||||
self.hidden = (totalDataCount == 0);
|
||||
}
|
||||
}];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#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
|
||||
+25
@@ -0,0 +1,25 @@
|
||||
// 代码地址: https://github.com/CoderMJLee/MJRefresh
|
||||
// 代码地址: http://code4app.com/ios/%E5%BF%AB%E9%80%9F%E9%9B%86%E6%88%90%E4%B8%8B%E6%8B%89%E4%B8%8A%E6%8B%89%E5%88%B7%E6%96%B0/52326ce26803fabc46000000
|
||||
// MJRefreshHeader.h
|
||||
// MJRefreshExample
|
||||
//
|
||||
// Created by MJ Lee on 15/3/4.
|
||||
// Copyright (c) 2015年 小码哥. All rights reserved.
|
||||
// 下拉刷新控件:负责监控用户下拉的状态
|
||||
|
||||
#import "MJRefreshComponent.h"
|
||||
|
||||
@interface MJRefreshHeader : MJRefreshComponent
|
||||
/** 创建header */
|
||||
+ (instancetype)headerWithRefreshingBlock:(MJRefreshComponentRefreshingBlock)refreshingBlock;
|
||||
/** 创建header */
|
||||
+ (instancetype)headerWithRefreshingTarget:(id)target refreshingAction:(SEL)action;
|
||||
|
||||
/** 这个key用来存储上一次下拉刷新成功的时间 */
|
||||
@property (copy, nonatomic) NSString *lastUpdatedTimeKey;
|
||||
/** 上一次下拉刷新成功的时间 */
|
||||
@property (strong, nonatomic, readonly) NSDate *lastUpdatedTime;
|
||||
|
||||
/** 忽略多少scrollView的contentInset的top */
|
||||
@property (assign, nonatomic) CGFloat ignoredScrollViewContentInsetTop;
|
||||
@end
|
||||
+158
@@ -0,0 +1,158 @@
|
||||
// 代码地址: https://github.com/CoderMJLee/MJRefresh
|
||||
// 代码地址: http://code4app.com/ios/%E5%BF%AB%E9%80%9F%E9%9B%86%E6%88%90%E4%B8%8B%E6%8B%89%E4%B8%8A%E6%8B%89%E5%88%B7%E6%96%B0/52326ce26803fabc46000000
|
||||
// MJRefreshHeader.m
|
||||
// MJRefreshExample
|
||||
//
|
||||
// Created by MJ Lee on 15/3/4.
|
||||
// Copyright (c) 2015年 小码哥. All rights reserved.
|
||||
//
|
||||
|
||||
#import "MJRefreshHeader.h"
|
||||
|
||||
@interface MJRefreshHeader()
|
||||
@property (assign, nonatomic) CGFloat insetTDelta;
|
||||
@end
|
||||
|
||||
@implementation MJRefreshHeader
|
||||
#pragma mark - 构造方法
|
||||
+ (instancetype)headerWithRefreshingBlock:(MJRefreshComponentRefreshingBlock)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)scrollViewContentOffsetDidChange:(NSDictionary *)change
|
||||
{
|
||||
[super scrollViewContentOffsetDidChange:change];
|
||||
|
||||
// 在刷新的refreshing状态
|
||||
if (self.state == MJRefreshStateRefreshing) {
|
||||
// 暂时保留
|
||||
if (self.window == nil) 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.scrollView.mj_insetT = insetT;
|
||||
|
||||
self.insetTDelta = _scrollViewOriginalInset.top - insetT;
|
||||
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;
|
||||
|
||||
// 保存刷新时间
|
||||
[[NSUserDefaults standardUserDefaults] setObject:[NSDate date] forKey:self.lastUpdatedTimeKey];
|
||||
[[NSUserDefaults standardUserDefaults] synchronize];
|
||||
|
||||
// 恢复inset和offset
|
||||
[UIView animateWithDuration:MJRefreshSlowAnimationDuration animations:^{
|
||||
self.scrollView.mj_insetT += self.insetTDelta;
|
||||
|
||||
// 自动调整透明度
|
||||
if (self.isAutomaticallyChangeAlpha) self.alpha = 0.0;
|
||||
} completion:^(BOOL finished) {
|
||||
self.pullingPercent = 0.0;
|
||||
|
||||
if (self.endRefreshingCompletionBlock) {
|
||||
self.endRefreshingCompletionBlock();
|
||||
}
|
||||
}];
|
||||
} else if (state == MJRefreshStateRefreshing) {
|
||||
MJRefreshDispatchAsyncOnMainQueue({
|
||||
[UIView animateWithDuration:MJRefreshFastAnimationDuration animations:^{
|
||||
if (self.scrollView.panGestureRecognizer.state != UIGestureRecognizerStateCancelled) {
|
||||
CGFloat top = self.scrollViewOriginalInset.top + self.mj_h;
|
||||
// 增加滚动区域top
|
||||
self.scrollView.mj_insetT = top;
|
||||
// 设置滚动位置
|
||||
CGPoint offset = self.scrollView.contentOffset;
|
||||
offset.y = -top;
|
||||
[self.scrollView setContentOffset:offset animated:NO];
|
||||
}
|
||||
} completion:^(BOOL finished) {
|
||||
[self executeRefreshingCallback];
|
||||
}];
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
#pragma mark - 公共方法
|
||||
- (NSDate *)lastUpdatedTime
|
||||
{
|
||||
return [[NSUserDefaults standardUserDefaults] objectForKey:self.lastUpdatedTimeKey];
|
||||
}
|
||||
|
||||
- (void)setIgnoredScrollViewContentInsetTop:(CGFloat)ignoredScrollViewContentInsetTop {
|
||||
_ignoredScrollViewContentInsetTop = ignoredScrollViewContentInsetTop;
|
||||
|
||||
self.mj_y = - self.mj_h - _ignoredScrollViewContentInsetTop;
|
||||
}
|
||||
|
||||
@end
|
||||
@@ -0,0 +1,17 @@
|
||||
//
|
||||
// MJRefreshAutoGifFooter.h
|
||||
// MJRefreshExample
|
||||
//
|
||||
// Created by MJ Lee on 15/4/24.
|
||||
// Copyright (c) 2015年 小码哥. All rights reserved.
|
||||
//
|
||||
|
||||
#import "MJRefreshAutoStateFooter.h"
|
||||
|
||||
@interface MJRefreshAutoGifFooter : MJRefreshAutoStateFooter
|
||||
@property (weak, nonatomic, readonly) UIImageView *gifView;
|
||||
|
||||
/** 设置state状态下的动画图片images 动画持续时间duration*/
|
||||
- (void)setImages:(NSArray *)images duration:(NSTimeInterval)duration forState:(MJRefreshState)state;
|
||||
- (void)setImages:(NSArray *)images forState:(MJRefreshState)state;
|
||||
@end
|
||||
@@ -0,0 +1,116 @@
|
||||
//
|
||||
// MJRefreshAutoGifFooter.m
|
||||
// MJRefreshExample
|
||||
//
|
||||
// Created by MJ Lee on 15/4/24.
|
||||
// Copyright (c) 2015年 小码哥. All rights reserved.
|
||||
//
|
||||
|
||||
#import "MJRefreshAutoGifFooter.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 - 公共方法
|
||||
- (void)setImages:(NSArray *)images duration:(NSTimeInterval)duration forState:(MJRefreshState)state
|
||||
{
|
||||
if (images == nil) return;
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
- (void)setImages:(NSArray *)images forState:(MJRefreshState)state
|
||||
{
|
||||
[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_textWith * 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
|
||||
|
||||
@@ -0,0 +1,14 @@
|
||||
//
|
||||
// MJRefreshAutoNormalFooter.h
|
||||
// MJRefreshExample
|
||||
//
|
||||
// Created by MJ Lee on 15/4/24.
|
||||
// Copyright (c) 2015年 小码哥. All rights reserved.
|
||||
//
|
||||
|
||||
#import "MJRefreshAutoStateFooter.h"
|
||||
|
||||
@interface MJRefreshAutoNormalFooter : MJRefreshAutoStateFooter
|
||||
/** 菊花的样式 */
|
||||
@property (assign, nonatomic) UIActivityIndicatorViewStyle activityIndicatorViewStyle;
|
||||
@end
|
||||
@@ -0,0 +1,69 @@
|
||||
//
|
||||
// MJRefreshAutoNormalFooter.m
|
||||
// MJRefreshExample
|
||||
//
|
||||
// Created by MJ Lee on 15/4/24.
|
||||
// Copyright (c) 2015年 小码哥. All rights reserved.
|
||||
//
|
||||
|
||||
#import "MJRefreshAutoNormalFooter.h"
|
||||
|
||||
@interface MJRefreshAutoNormalFooter()
|
||||
@property (weak, nonatomic) UIActivityIndicatorView *loadingView;
|
||||
@end
|
||||
|
||||
@implementation MJRefreshAutoNormalFooter
|
||||
#pragma mark - 懒加载子控件
|
||||
- (UIActivityIndicatorView *)loadingView
|
||||
{
|
||||
if (!_loadingView) {
|
||||
UIActivityIndicatorView *loadingView = [[UIActivityIndicatorView alloc] initWithActivityIndicatorStyle:self.activityIndicatorViewStyle];
|
||||
loadingView.hidesWhenStopped = YES;
|
||||
[self addSubview:_loadingView = loadingView];
|
||||
}
|
||||
return _loadingView;
|
||||
}
|
||||
|
||||
- (void)setActivityIndicatorViewStyle:(UIActivityIndicatorViewStyle)activityIndicatorViewStyle
|
||||
{
|
||||
_activityIndicatorViewStyle = activityIndicatorViewStyle;
|
||||
|
||||
self.loadingView = nil;
|
||||
[self setNeedsLayout];
|
||||
}
|
||||
#pragma mark - 重写父类的方法
|
||||
- (void)prepare
|
||||
{
|
||||
[super prepare];
|
||||
|
||||
self.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_textWith * 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
|
||||
@@ -0,0 +1,22 @@
|
||||
//
|
||||
// MJRefreshAutoStateFooter.h
|
||||
// MJRefreshExample
|
||||
//
|
||||
// Created by MJ Lee on 15/6/13.
|
||||
// Copyright © 2015年 小码哥. All rights reserved.
|
||||
//
|
||||
|
||||
#import "MJRefreshAutoFooter.h"
|
||||
|
||||
@interface MJRefreshAutoStateFooter : MJRefreshAutoFooter
|
||||
/** 文字距离圈圈、箭头的距离 */
|
||||
@property (assign, nonatomic) CGFloat labelLeftInset;
|
||||
/** 显示刷新状态的label */
|
||||
@property (weak, nonatomic, readonly) UILabel *stateLabel;
|
||||
|
||||
/** 设置state状态下的文字 */
|
||||
- (void)setTitle:(NSString *)title forState:(MJRefreshState)state;
|
||||
|
||||
/** 隐藏刷新状态的文字 */
|
||||
@property (assign, nonatomic, getter=isRefreshingTitleHidden) BOOL refreshingTitleHidden;
|
||||
@end
|
||||
@@ -0,0 +1,92 @@
|
||||
//
|
||||
// MJRefreshAutoStateFooter.m
|
||||
// MJRefreshExample
|
||||
//
|
||||
// Created by MJ Lee on 15/6/13.
|
||||
// Copyright © 2015年 小码哥. All rights reserved.
|
||||
//
|
||||
|
||||
#import "MJRefreshAutoStateFooter.h"
|
||||
|
||||
@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 - 公共方法
|
||||
- (void)setTitle:(NSString *)title forState:(MJRefreshState)state
|
||||
{
|
||||
if (title == nil) return;
|
||||
self.stateTitles[@(state)] = title;
|
||||
self.stateLabel.text = self.stateTitles[@(self.state)];
|
||||
}
|
||||
|
||||
#pragma mark - 私有方法
|
||||
- (void)stateLabelClick
|
||||
{
|
||||
if (self.state == MJRefreshStateIdle) {
|
||||
[self beginRefreshing];
|
||||
}
|
||||
}
|
||||
|
||||
#pragma mark - 重写父类的方法
|
||||
- (void)prepare
|
||||
{
|
||||
[super prepare];
|
||||
|
||||
// 初始化间距
|
||||
self.labelLeftInset = MJRefreshLabelLeftInset;
|
||||
|
||||
// 初始化文字
|
||||
[self setTitle:[NSBundle mj_localizedStringForKey:MJRefreshAutoFooterIdleText] forState:MJRefreshStateIdle];
|
||||
[self setTitle:[NSBundle mj_localizedStringForKey:MJRefreshAutoFooterRefreshingText] forState:MJRefreshStateRefreshing];
|
||||
[self setTitle:[NSBundle mj_localizedStringForKey:MJRefreshAutoFooterNoMoreDataText] forState:MJRefreshStateNoMoreData];
|
||||
|
||||
// 监听label
|
||||
self.stateLabel.userInteractionEnabled = YES;
|
||||
[self.stateLabel addGestureRecognizer:[[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(stateLabelClick)]];
|
||||
}
|
||||
|
||||
- (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
|
||||
@@ -0,0 +1,17 @@
|
||||
//
|
||||
// MJRefreshBackGifFooter.h
|
||||
// MJRefreshExample
|
||||
//
|
||||
// Created by MJ Lee on 15/4/24.
|
||||
// Copyright (c) 2015年 小码哥. All rights reserved.
|
||||
//
|
||||
|
||||
#import "MJRefreshBackStateFooter.h"
|
||||
|
||||
@interface MJRefreshBackGifFooter : MJRefreshBackStateFooter
|
||||
@property (weak, nonatomic, readonly) UIImageView *gifView;
|
||||
|
||||
/** 设置state状态下的动画图片images 动画持续时间duration*/
|
||||
- (void)setImages:(NSArray *)images duration:(NSTimeInterval)duration forState:(MJRefreshState)state;
|
||||
- (void)setImages:(NSArray *)images forState:(MJRefreshState)state;
|
||||
@end
|
||||
@@ -0,0 +1,127 @@
|
||||
//
|
||||
// MJRefreshBackGifFooter.m
|
||||
// MJRefreshExample
|
||||
//
|
||||
// Created by MJ Lee on 15/4/24.
|
||||
// Copyright (c) 2015年 小码哥. All rights reserved.
|
||||
//
|
||||
|
||||
#import "MJRefreshBackGifFooter.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 - 公共方法
|
||||
- (void)setImages:(NSArray *)images duration:(NSTimeInterval)duration forState:(MJRefreshState)state
|
||||
{
|
||||
if (images == nil) return;
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
- (void)setImages:(NSArray *)images forState:(MJRefreshState)state
|
||||
{
|
||||
[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_textWith * 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
|
||||
@@ -0,0 +1,15 @@
|
||||
//
|
||||
// MJRefreshBackNormalFooter.h
|
||||
// MJRefreshExample
|
||||
//
|
||||
// Created by MJ Lee on 15/4/24.
|
||||
// Copyright (c) 2015年 小码哥. All rights reserved.
|
||||
//
|
||||
|
||||
#import "MJRefreshBackStateFooter.h"
|
||||
|
||||
@interface MJRefreshBackNormalFooter : MJRefreshBackStateFooter
|
||||
@property (weak, nonatomic, readonly) UIImageView *arrowView;
|
||||
/** 菊花的样式 */
|
||||
@property (assign, nonatomic) UIActivityIndicatorViewStyle activityIndicatorViewStyle;
|
||||
@end
|
||||
@@ -0,0 +1,123 @@
|
||||
//
|
||||
// MJRefreshBackNormalFooter.m
|
||||
// MJRefreshExample
|
||||
//
|
||||
// Created by MJ Lee on 15/4/24.
|
||||
// Copyright (c) 2015年 小码哥. All rights reserved.
|
||||
//
|
||||
|
||||
#import "MJRefreshBackNormalFooter.h"
|
||||
#import "NSBundle+MJRefresh.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:self.activityIndicatorViewStyle];
|
||||
loadingView.hidesWhenStopped = YES;
|
||||
[self addSubview:_loadingView = loadingView];
|
||||
}
|
||||
return _loadingView;
|
||||
}
|
||||
|
||||
- (void)setActivityIndicatorViewStyle:(UIActivityIndicatorViewStyle)activityIndicatorViewStyle
|
||||
{
|
||||
_activityIndicatorViewStyle = activityIndicatorViewStyle;
|
||||
|
||||
self.loadingView = nil;
|
||||
[self setNeedsLayout];
|
||||
}
|
||||
#pragma mark - 重写父类的方法
|
||||
- (void)prepare
|
||||
{
|
||||
[super prepare];
|
||||
|
||||
self.activityIndicatorViewStyle = UIActivityIndicatorViewStyleGray;
|
||||
}
|
||||
|
||||
- (void)placeSubviews
|
||||
{
|
||||
[super placeSubviews];
|
||||
|
||||
// 箭头的中心点
|
||||
CGFloat arrowCenterX = self.mj_w * 0.5;
|
||||
if (!self.stateLabel.hidden) {
|
||||
arrowCenterX -= self.labelLeftInset + self.stateLabel.mj_textWith * 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:MJRefreshSlowAnimationDuration animations:^{
|
||||
self.loadingView.alpha = 0.0;
|
||||
} completion:^(BOOL finished) {
|
||||
// 防止动画结束后,状态已经不是MJRefreshStateIdle
|
||||
if (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:MJRefreshFastAnimationDuration animations:^{
|
||||
self.arrowView.transform = CGAffineTransformMakeRotation(0.000001 - M_PI);
|
||||
}];
|
||||
}
|
||||
} else if (state == MJRefreshStatePulling) {
|
||||
self.arrowView.hidden = NO;
|
||||
[self.loadingView stopAnimating];
|
||||
[UIView animateWithDuration:MJRefreshFastAnimationDuration 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
|
||||
@@ -0,0 +1,21 @@
|
||||
//
|
||||
// MJRefreshBackStateFooter.h
|
||||
// MJRefreshExample
|
||||
//
|
||||
// Created by MJ Lee on 15/6/13.
|
||||
// Copyright © 2015年 小码哥. All rights reserved.
|
||||
//
|
||||
|
||||
#import "MJRefreshBackFooter.h"
|
||||
|
||||
@interface MJRefreshBackStateFooter : MJRefreshBackFooter
|
||||
/** 文字距离圈圈、箭头的距离 */
|
||||
@property (assign, nonatomic) CGFloat labelLeftInset;
|
||||
/** 显示刷新状态的label */
|
||||
@property (weak, nonatomic, readonly) UILabel *stateLabel;
|
||||
/** 设置state状态下的文字 */
|
||||
- (void)setTitle:(NSString *)title forState:(MJRefreshState)state;
|
||||
|
||||
/** 获取state状态下的title */
|
||||
- (NSString *)titleForState:(MJRefreshState)state;
|
||||
@end
|
||||
@@ -0,0 +1,82 @@
|
||||
//
|
||||
// MJRefreshBackStateFooter.m
|
||||
// MJRefreshExample
|
||||
//
|
||||
// Created by MJ Lee on 15/6/13.
|
||||
// Copyright © 2015年 小码哥. All rights reserved.
|
||||
//
|
||||
|
||||
#import "MJRefreshBackStateFooter.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 - 公共方法
|
||||
- (void)setTitle:(NSString *)title forState:(MJRefreshState)state
|
||||
{
|
||||
if (title == nil) return;
|
||||
self.stateTitles[@(state)] = title;
|
||||
self.stateLabel.text = self.stateTitles[@(self.state)];
|
||||
}
|
||||
|
||||
- (NSString *)titleForState:(MJRefreshState)state {
|
||||
return self.stateTitles[@(state)];
|
||||
}
|
||||
|
||||
#pragma mark - 重写父类的方法
|
||||
- (void)prepare
|
||||
{
|
||||
[super prepare];
|
||||
|
||||
// 初始化间距
|
||||
self.labelLeftInset = MJRefreshLabelLeftInset;
|
||||
|
||||
// 初始化文字
|
||||
[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];
|
||||
}
|
||||
|
||||
- (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
|
||||
@@ -0,0 +1,17 @@
|
||||
//
|
||||
// MJRefreshGifHeader.h
|
||||
// MJRefreshExample
|
||||
//
|
||||
// Created by MJ Lee on 15/4/24.
|
||||
// Copyright (c) 2015年 小码哥. All rights reserved.
|
||||
//
|
||||
|
||||
#import "MJRefreshStateHeader.h"
|
||||
|
||||
@interface MJRefreshGifHeader : MJRefreshStateHeader
|
||||
@property (weak, nonatomic, readonly) UIImageView *gifView;
|
||||
|
||||
/** 设置state状态下的动画图片images 动画持续时间duration*/
|
||||
- (void)setImages:(NSArray *)images duration:(NSTimeInterval)duration forState:(MJRefreshState)state;
|
||||
- (void)setImages:(NSArray *)images forState:(MJRefreshState)state;
|
||||
@end
|
||||
@@ -0,0 +1,133 @@
|
||||
//
|
||||
// MJRefreshGifHeader.m
|
||||
// MJRefreshExample
|
||||
//
|
||||
// Created by MJ Lee on 15/4/24.
|
||||
// Copyright (c) 2015年 小码哥. All rights reserved.
|
||||
//
|
||||
|
||||
#import "MJRefreshGifHeader.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 - 公共方法
|
||||
- (void)setImages:(NSArray *)images duration:(NSTimeInterval)duration forState:(MJRefreshState)state
|
||||
{
|
||||
if (images == nil) return;
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
- (void)setImages:(NSArray *)images forState:(MJRefreshState)state
|
||||
{
|
||||
[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_textWith;
|
||||
CGFloat timeWidth = 0.0;
|
||||
if (!self.lastUpdatedTimeLabel.hidden) {
|
||||
timeWidth = self.lastUpdatedTimeLabel.mj_textWith;
|
||||
}
|
||||
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
|
||||
@@ -0,0 +1,15 @@
|
||||
//
|
||||
// MJRefreshNormalHeader.h
|
||||
// MJRefreshExample
|
||||
//
|
||||
// Created by MJ Lee on 15/4/24.
|
||||
// Copyright (c) 2015年 小码哥. All rights reserved.
|
||||
//
|
||||
|
||||
#import "MJRefreshStateHeader.h"
|
||||
|
||||
@interface MJRefreshNormalHeader : MJRefreshStateHeader
|
||||
@property (weak, nonatomic, readonly) UIImageView *arrowView;
|
||||
/** 菊花的样式 */
|
||||
@property (assign, nonatomic) UIActivityIndicatorViewStyle activityIndicatorViewStyle;
|
||||
@end
|
||||
@@ -0,0 +1,127 @@
|
||||
//
|
||||
// MJRefreshNormalHeader.m
|
||||
// MJRefreshExample
|
||||
//
|
||||
// Created by MJ Lee on 15/4/24.
|
||||
// Copyright (c) 2015年 小码哥. All rights reserved.
|
||||
//
|
||||
|
||||
#import "MJRefreshNormalHeader.h"
|
||||
#import "NSBundle+MJRefresh.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:self.activityIndicatorViewStyle];
|
||||
loadingView.hidesWhenStopped = YES;
|
||||
[self addSubview:_loadingView = loadingView];
|
||||
}
|
||||
return _loadingView;
|
||||
}
|
||||
|
||||
#pragma mark - 公共方法
|
||||
- (void)setActivityIndicatorViewStyle:(UIActivityIndicatorViewStyle)activityIndicatorViewStyle
|
||||
{
|
||||
_activityIndicatorViewStyle = activityIndicatorViewStyle;
|
||||
|
||||
self.loadingView = nil;
|
||||
[self setNeedsLayout];
|
||||
}
|
||||
|
||||
#pragma mark - 重写父类的方法
|
||||
- (void)prepare
|
||||
{
|
||||
[super prepare];
|
||||
|
||||
self.activityIndicatorViewStyle = UIActivityIndicatorViewStyleGray;
|
||||
}
|
||||
|
||||
- (void)placeSubviews
|
||||
{
|
||||
[super placeSubviews];
|
||||
|
||||
// 箭头的中心点
|
||||
CGFloat arrowCenterX = self.mj_w * 0.5;
|
||||
if (!self.stateLabel.hidden) {
|
||||
CGFloat stateWidth = self.stateLabel.mj_textWith;
|
||||
CGFloat timeWidth = 0.0;
|
||||
if (!self.lastUpdatedTimeLabel.hidden) {
|
||||
timeWidth = self.lastUpdatedTimeLabel.mj_textWith;
|
||||
}
|
||||
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:MJRefreshSlowAnimationDuration 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:MJRefreshFastAnimationDuration animations:^{
|
||||
self.arrowView.transform = CGAffineTransformIdentity;
|
||||
}];
|
||||
}
|
||||
} else if (state == MJRefreshStatePulling) {
|
||||
[self.loadingView stopAnimating];
|
||||
self.arrowView.hidden = NO;
|
||||
[UIView animateWithDuration:MJRefreshFastAnimationDuration 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
|
||||
@@ -0,0 +1,25 @@
|
||||
//
|
||||
// MJRefreshStateHeader.h
|
||||
// MJRefreshExample
|
||||
//
|
||||
// Created by MJ Lee on 15/4/24.
|
||||
// Copyright (c) 2015年 小码哥. All rights reserved.
|
||||
//
|
||||
|
||||
#import "MJRefreshHeader.h"
|
||||
|
||||
@interface MJRefreshStateHeader : MJRefreshHeader
|
||||
#pragma mark - 刷新时间相关
|
||||
/** 利用这个block来决定显示的更新时间文字 */
|
||||
@property (copy, nonatomic) NSString *(^lastUpdatedTimeText)(NSDate *lastUpdatedTime);
|
||||
/** 显示上一次刷新时间的label */
|
||||
@property (weak, nonatomic, readonly) UILabel *lastUpdatedTimeLabel;
|
||||
|
||||
#pragma mark - 状态相关
|
||||
/** 文字距离圈圈、箭头的距离 */
|
||||
@property (assign, nonatomic) CGFloat labelLeftInset;
|
||||
/** 显示刷新状态的label */
|
||||
@property (weak, nonatomic, readonly) UILabel *stateLabel;
|
||||
/** 设置state状态下的文字 */
|
||||
- (void)setTitle:(NSString *)title forState:(MJRefreshState)state;
|
||||
@end
|
||||
@@ -0,0 +1,167 @@
|
||||
//
|
||||
// MJRefreshStateHeader.m
|
||||
// MJRefreshExample
|
||||
//
|
||||
// Created by MJ Lee on 15/4/24.
|
||||
// Copyright (c) 2015年 小码哥. All rights reserved.
|
||||
//
|
||||
|
||||
#import "MJRefreshStateHeader.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;
|
||||
}
|
||||
|
||||
#pragma mark - 公共方法
|
||||
- (void)setTitle:(NSString *)title forState:(MJRefreshState)state
|
||||
{
|
||||
if (title == nil) return;
|
||||
self.stateTitles[@(state)] = title;
|
||||
self.stateLabel.text = self.stateTitles[@(self.state)];
|
||||
}
|
||||
|
||||
#pragma mark - 日历获取在9.x之后的系统使用currentCalendar会出异常。在8.0之后使用系统新API。
|
||||
- (NSCalendar *)currentCalendar {
|
||||
if ([NSCalendar respondsToSelector:@selector(calendarWithIdentifier:)]) {
|
||||
return [NSCalendar calendarWithIdentifier:NSCalendarIdentifierGregorian];
|
||||
}
|
||||
return [NSCalendar currentCalendar];
|
||||
}
|
||||
|
||||
#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 = [self currentCalendar];
|
||||
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]];
|
||||
}
|
||||
}
|
||||
|
||||
#pragma mark - 覆盖父类的方法
|
||||
- (void)prepare
|
||||
{
|
||||
[super prepare];
|
||||
|
||||
// 初始化间距
|
||||
self.labelLeftInset = MJRefreshLabelLeftInset;
|
||||
|
||||
// 初始化文字
|
||||
[self setTitle:[NSBundle mj_localizedStringForKey:MJRefreshHeaderIdleText] forState:MJRefreshStateIdle];
|
||||
[self setTitle:[NSBundle mj_localizedStringForKey:MJRefreshHeaderPullingText] forState:MJRefreshStatePulling];
|
||||
[self setTitle:[NSBundle mj_localizedStringForKey:MJRefreshHeaderRefreshingText] forState:MJRefreshStateRefreshing];
|
||||
}
|
||||
|
||||
- (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
|
||||
BIN
Binary file not shown.
|
After Width: | Height: | Size: 1.0 KiB |
@@ -0,0 +1,16 @@
|
||||
"MJRefreshHeaderIdleText" = "Pull down to refresh";
|
||||
"MJRefreshHeaderPullingText" = "Release to refresh";
|
||||
"MJRefreshHeaderRefreshingText" = "Loading...";
|
||||
|
||||
"MJRefreshAutoFooterIdleText" = "Tap or pull up to load more";
|
||||
"MJRefreshAutoFooterRefreshingText" = "Loading...";
|
||||
"MJRefreshAutoFooterNoMoreDataText" = "No more data";
|
||||
|
||||
"MJRefreshBackFooterIdleText" = "Pull up to load more";
|
||||
"MJRefreshBackFooterPullingText" = "Release to load more.";
|
||||
"MJRefreshBackFooterRefreshingText" = "Loading...";
|
||||
"MJRefreshBackFooterNoMoreDataText" = "No more data";
|
||||
|
||||
"MJRefreshHeaderLastTimeText" = "Last updated: ";
|
||||
"MJRefreshHeaderDateTodayText" = "Today";
|
||||
"MJRefreshHeaderNoneLastDateText" = "No record";
|
||||
Binary file not shown.
@@ -0,0 +1,16 @@
|
||||
"MJRefreshHeaderIdleText" = "下拉可以刷新";
|
||||
"MJRefreshHeaderPullingText" = "鬆開立即刷新";
|
||||
"MJRefreshHeaderRefreshingText" = "正在刷新數據中...";
|
||||
|
||||
"MJRefreshAutoFooterIdleText" = "點擊或上拉加載更多";
|
||||
"MJRefreshAutoFooterRefreshingText" = "正在加載更多的數據...";
|
||||
"MJRefreshAutoFooterNoMoreDataText" = "已經全部加載完畢";
|
||||
|
||||
"MJRefreshBackFooterIdleText" = "上拉可以加載更多";
|
||||
"MJRefreshBackFooterPullingText" = "鬆開立即加載更多";
|
||||
"MJRefreshBackFooterRefreshingText" = "正在加載更多的數據...";
|
||||
"MJRefreshBackFooterNoMoreDataText" = "已經全部加載完畢";
|
||||
|
||||
"MJRefreshHeaderLastTimeText" = "最後更新:";
|
||||
"MJRefreshHeaderDateTodayText" = "今天";
|
||||
"MJRefreshHeaderNoneLastDateText" = "無記錄";
|
||||
Generated
+14
@@ -0,0 +1,14 @@
|
||||
// 代码地址: https://github.com/CoderMJLee/MJRefresh
|
||||
// 代码地址: http://code4app.com/ios/%E5%BF%AB%E9%80%9F%E9%9B%86%E6%88%90%E4%B8%8B%E6%8B%89%E4%B8%8A%E6%8B%89%E5%88%B7%E6%96%B0/52326ce26803fabc46000000
|
||||
|
||||
#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"
|
||||
+76
@@ -0,0 +1,76 @@
|
||||
// 代码地址: https://github.com/CoderMJLee/MJRefresh
|
||||
// 代码地址: http://code4app.com/ios/%E5%BF%AB%E9%80%9F%E9%9B%86%E6%88%90%E4%B8%8B%E6%8B%89%E4%B8%8A%E6%8B%89%E5%88%B7%E6%96%B0/52326ce26803fabc46000000
|
||||
#import <UIKit/UIKit.h>
|
||||
#import <objc/message.h>
|
||||
|
||||
// 弱引用
|
||||
#define MJWeakSelf __weak typeof(self) weakSelf = self;
|
||||
|
||||
// 日志输出
|
||||
#ifdef DEBUG
|
||||
#define MJRefreshLog(...) NSLog(__VA_ARGS__)
|
||||
#else
|
||||
#define MJRefreshLog(...)
|
||||
#endif
|
||||
|
||||
// 过期提醒
|
||||
#define MJRefreshDeprecated(instead) NS_DEPRECATED(2_0, 2_0, 2_0, 2_0, instead)
|
||||
|
||||
// 运行时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 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 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;
|
||||
|
||||
// 状态检查
|
||||
#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} \
|
||||
});
|
||||
|
||||
+33
@@ -0,0 +1,33 @@
|
||||
// 代码地址: https://github.com/CoderMJLee/MJRefresh
|
||||
// 代码地址: http://code4app.com/ios/%E5%BF%AB%E9%80%9F%E9%9B%86%E6%88%90%E4%B8%8B%E6%8B%89%E4%B8%8A%E6%8B%89%E5%88%B7%E6%96%B0/52326ce26803fabc46000000
|
||||
#import <UIKit/UIKit.h>
|
||||
|
||||
const CGFloat MJRefreshLabelLeftInset = 25;
|
||||
const CGFloat MJRefreshHeaderHeight = 54.0;
|
||||
const CGFloat MJRefreshFooterHeight = 44.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 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";
|
||||
+16
@@ -0,0 +1,16 @@
|
||||
//
|
||||
// NSBundle+MJRefresh.h
|
||||
// MJRefreshExample
|
||||
//
|
||||
// Created by MJ Lee on 16/6/13.
|
||||
// Copyright © 2016年 小码哥. All rights reserved.
|
||||
//
|
||||
|
||||
#import <UIKit/UIKit.h>
|
||||
|
||||
@interface NSBundle (MJRefresh)
|
||||
+ (instancetype)mj_refreshBundle;
|
||||
+ (UIImage *)mj_arrowImage;
|
||||
+ (NSString *)mj_localizedStringForKey:(NSString *)key value:(NSString *)value;
|
||||
+ (NSString *)mj_localizedStringForKey:(NSString *)key;
|
||||
@end
|
||||
+61
@@ -0,0 +1,61 @@
|
||||
//
|
||||
// NSBundle+MJRefresh.m
|
||||
// MJRefreshExample
|
||||
//
|
||||
// Created by MJ Lee on 16/6/13.
|
||||
// Copyright © 2016年 小码哥. All rights reserved.
|
||||
//
|
||||
|
||||
#import "NSBundle+MJRefresh.h"
|
||||
#import "MJRefreshComponent.h"
|
||||
|
||||
@implementation NSBundle (MJRefresh)
|
||||
+ (instancetype)mj_refreshBundle
|
||||
{
|
||||
static NSBundle *refreshBundle = nil;
|
||||
if (refreshBundle == nil) {
|
||||
// 这里不使用mainBundle是为了适配pod 1.x和0.x
|
||||
refreshBundle = [NSBundle bundleWithPath:[[NSBundle bundleForClass:[MJRefreshComponent class]] 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;
|
||||
}
|
||||
|
||||
+ (NSString *)mj_localizedStringForKey:(NSString *)key
|
||||
{
|
||||
return [self mj_localizedStringForKey:key value:nil];
|
||||
}
|
||||
|
||||
+ (NSString *)mj_localizedStringForKey:(NSString *)key value:(NSString *)value
|
||||
{
|
||||
static NSBundle *bundle = nil;
|
||||
if (bundle == nil) {
|
||||
// (iOS获取的语言字符串比较不稳定)目前框架只处理en、zh-Hans、zh-Hant三种情况,其他按照系统默认处理
|
||||
NSString *language = [NSLocale preferredLanguages].firstObject;
|
||||
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 {
|
||||
language = @"en";
|
||||
}
|
||||
|
||||
// 从MJRefresh.bundle中查找资源
|
||||
bundle = [NSBundle bundleWithPath:[[NSBundle mj_refreshBundle] pathForResource:language ofType:@"lproj"]];
|
||||
}
|
||||
value = [bundle localizedStringForKey:key value:value table:nil];
|
||||
return [[NSBundle mainBundle] localizedStringForKey:key value:value table:nil];
|
||||
}
|
||||
@end
|
||||
+25
@@ -0,0 +1,25 @@
|
||||
// 代码地址: https://github.com/CoderMJLee/MJRefresh
|
||||
// 代码地址: http://code4app.com/ios/%E5%BF%AB%E9%80%9F%E9%9B%86%E6%88%90%E4%B8%8B%E6%8B%89%E4%B8%8A%E6%8B%89%E5%88%B7%E6%96%B0/52326ce26803fabc46000000
|
||||
// UIScrollView+Extension.h
|
||||
// MJRefreshExample
|
||||
//
|
||||
// Created by MJ Lee on 14-5-28.
|
||||
// Copyright (c) 2014年 小码哥. All rights reserved.
|
||||
//
|
||||
|
||||
#import <UIKit/UIKit.h>
|
||||
|
||||
@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
|
||||
+154
@@ -0,0 +1,154 @@
|
||||
// 代码地址: https://github.com/CoderMJLee/MJRefresh
|
||||
// 代码地址: http://code4app.com/ios/%E5%BF%AB%E9%80%9F%E9%9B%86%E6%88%90%E4%B8%8B%E6%8B%89%E4%B8%8A%E6%8B%89%E5%88%B7%E6%96%B0/52326ce26803fabc46000000
|
||||
// UIScrollView+Extension.m
|
||||
// MJRefreshExample
|
||||
//
|
||||
// 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)initialize
|
||||
{
|
||||
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
|
||||
+26
@@ -0,0 +1,26 @@
|
||||
// 代码地址: https://github.com/CoderMJLee/MJRefresh
|
||||
// 代码地址: http://code4app.com/ios/%E5%BF%AB%E9%80%9F%E9%9B%86%E6%88%90%E4%B8%8B%E6%8B%89%E4%B8%8A%E6%8B%89%E5%88%B7%E6%96%B0/52326ce26803fabc46000000
|
||||
// UIScrollView+MJRefresh.h
|
||||
// MJRefreshExample
|
||||
//
|
||||
// Created by MJ Lee on 15/3/4.
|
||||
// Copyright (c) 2015年 小码哥. All rights reserved.
|
||||
// 给ScrollView增加下拉刷新、上拉刷新的功能
|
||||
|
||||
#import <UIKit/UIKit.h>
|
||||
#import "MJRefreshConst.h"
|
||||
|
||||
@class MJRefreshHeader, MJRefreshFooter;
|
||||
|
||||
@interface UIScrollView (MJRefresh)
|
||||
/** 下拉刷新控件 */
|
||||
@property (strong, nonatomic) MJRefreshHeader *mj_header;
|
||||
@property (strong, nonatomic) MJRefreshHeader *header MJRefreshDeprecated("使用mj_header");
|
||||
/** 上拉刷新控件 */
|
||||
@property (strong, nonatomic) MJRefreshFooter *mj_footer;
|
||||
@property (strong, nonatomic) MJRefreshFooter *footer MJRefreshDeprecated("使用mj_footer");
|
||||
|
||||
#pragma mark - other
|
||||
- (NSInteger)mj_totalDataCount;
|
||||
@property (copy, nonatomic) void (^mj_reloadDataBlock)(NSInteger totalDataCount);
|
||||
@end
|
||||
+159
@@ -0,0 +1,159 @@
|
||||
// 代码地址: https://github.com/CoderMJLee/MJRefresh
|
||||
// 代码地址: http://code4app.com/ios/%E5%BF%AB%E9%80%9F%E9%9B%86%E6%88%90%E4%B8%8B%E6%8B%89%E4%B8%8A%E6%8B%89%E5%88%B7%E6%96%B0/52326ce26803fabc46000000
|
||||
// UIScrollView+MJRefresh.m
|
||||
// MJRefreshExample
|
||||
//
|
||||
// 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 <objc/runtime.h>
|
||||
|
||||
@implementation NSObject (MJRefresh)
|
||||
|
||||
+ (void)exchangeInstanceMethod1:(SEL)method1 method2:(SEL)method2
|
||||
{
|
||||
method_exchangeImplementations(class_getInstanceMethod(self, method1), class_getInstanceMethod(self, method2));
|
||||
}
|
||||
|
||||
+ (void)exchangeClassMethod1:(SEL)method1 method2:(SEL)method2
|
||||
{
|
||||
method_exchangeImplementations(class_getClassMethod(self, method1), class_getClassMethod(self, method2));
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@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];
|
||||
[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];
|
||||
[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 - 过期
|
||||
- (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;
|
||||
}
|
||||
|
||||
static const char MJRefreshReloadDataBlockKey = '\0';
|
||||
- (void)setMj_reloadDataBlock:(void (^)(NSInteger))mj_reloadDataBlock
|
||||
{
|
||||
[self willChangeValueForKey:@"mj_reloadDataBlock"]; // KVO
|
||||
objc_setAssociatedObject(self, &MJRefreshReloadDataBlockKey, mj_reloadDataBlock, OBJC_ASSOCIATION_COPY_NONATOMIC);
|
||||
[self didChangeValueForKey:@"mj_reloadDataBlock"]; // KVO
|
||||
}
|
||||
|
||||
- (void (^)(NSInteger))mj_reloadDataBlock
|
||||
{
|
||||
return objc_getAssociatedObject(self, &MJRefreshReloadDataBlockKey);
|
||||
}
|
||||
|
||||
- (void)executeReloadDataBlock
|
||||
{
|
||||
!self.mj_reloadDataBlock ? : self.mj_reloadDataBlock(self.mj_totalDataCount);
|
||||
}
|
||||
@end
|
||||
|
||||
@implementation UITableView (MJRefresh)
|
||||
|
||||
+ (void)load
|
||||
{
|
||||
[self exchangeInstanceMethod1:@selector(reloadData) method2:@selector(mj_reloadData)];
|
||||
}
|
||||
|
||||
- (void)mj_reloadData
|
||||
{
|
||||
[self mj_reloadData];
|
||||
|
||||
[self executeReloadDataBlock];
|
||||
}
|
||||
@end
|
||||
|
||||
@implementation UICollectionView (MJRefresh)
|
||||
|
||||
+ (void)load
|
||||
{
|
||||
[self exchangeInstanceMethod1:@selector(reloadData) method2:@selector(mj_reloadData)];
|
||||
}
|
||||
|
||||
- (void)mj_reloadData
|
||||
{
|
||||
[self mj_reloadData];
|
||||
|
||||
[self executeReloadDataBlock];
|
||||
}
|
||||
@end
|
||||
+19
@@ -0,0 +1,19 @@
|
||||
// 代码地址: https://github.com/CoderMJLee/MJRefresh
|
||||
// 代码地址: http://code4app.com/ios/%E5%BF%AB%E9%80%9F%E9%9B%86%E6%88%90%E4%B8%8B%E6%8B%89%E4%B8%8A%E6%8B%89%E5%88%B7%E6%96%B0/52326ce26803fabc46000000
|
||||
// UIView+Extension.h
|
||||
// MJRefreshExample
|
||||
//
|
||||
// Created by MJ Lee on 14-5-28.
|
||||
// Copyright (c) 2014年 小码哥. All rights reserved.
|
||||
//
|
||||
|
||||
#import <UIKit/UIKit.h>
|
||||
|
||||
@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
|
||||
+84
@@ -0,0 +1,84 @@
|
||||
// 代码地址: https://github.com/CoderMJLee/MJRefresh
|
||||
// 代码地址: http://code4app.com/ios/%E5%BF%AB%E9%80%9F%E9%9B%86%E6%88%90%E4%B8%8B%E6%8B%89%E4%B8%8A%E6%8B%89%E5%88%B7%E6%96%B0/52326ce26803fabc46000000
|
||||
// UIView+Extension.m
|
||||
// MJRefreshExample
|
||||
//
|
||||
// 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
|
||||
Generated
+362
@@ -0,0 +1,362 @@
|
||||

|
||||
## MJRefresh
|
||||
* An easy way to use pull-to-refresh
|
||||
|
||||
## Contents
|
||||
* 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)
|
||||
* 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)
|
||||
* [UIWebView01-The drop-down refresh](#UIWebView01-The_drop-down_refresh)
|
||||
* [Hope](#Hope)
|
||||
|
||||
## <a id="Support_what_kinds_of_controls_to_refresh"></a>Support what kinds of controls to refresh
|
||||
* `UIScrollView`、`UITableView`、`UICollectionView`、`UIWebView`
|
||||
|
||||
## <a id="How_to_use_MJRefresh"></a>How to use MJRefresh
|
||||
* Installation with CocoaPods:`pod '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;
|
||||
|
||||
/** Automaticlly show or hidden by the count of data(Show-have data,Hidden- no data) */
|
||||
@property (assign, nonatomic) BOOL automaticallyHidden;
|
||||
@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="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.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.header = [MJRefreshNormalHeader headerWithRefreshingTarget:self refreshingAction:@selector(loadNewData)];
|
||||
|
||||
// Enter the refresh status immediately
|
||||
[self.tableView.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="UIWebView01-The_drop-down_refresh"></a>UIWebView01-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>=6.0
|
||||
* iPhone \ iPad screen anyway
|
||||
|
||||
## <a id="Hope"></a>Hope
|
||||
* If you find bug when used,Hope you can Issues me,Thank you or try to download the latest code of this framework to see the BUG has been fixed or not)
|
||||
* If you find the function is not enough when used,Hope you can Issues me,I very much to add more useful function to this framework ,Thank you !
|
||||
* If you want to contribute code for MJRefresh,please Pull Requests me
|
||||
* If you use MJRefresh in your develop app,Hope you can go to[CocoaControls](https://www.cocoacontrols.com/controls/mjrefresh)to add the iTunes path
|
||||
of you app,I Will install your app,and according to the usage of many app,to be a better design and improve to MJRefresh,Thank you !
|
||||
* StepO1(WeChat is just an Example,Explore“Your app name itunes”)
|
||||

|
||||
* StepO2
|
||||

|
||||
* StepO3
|
||||

|
||||
* StepO4
|
||||

|
||||
Reference in New Issue
Block a user