Browse Source

refactor for easier use

M了个J 11 years ago
parent
commit
5a17fc60b2

+ 12 - 0
MJRefreshExample/MJRefreshExample.xcodeproj/project.pbxproj

@@ -8,6 +8,8 @@
 
 /* Begin PBXBuildFile section */
 		2D1D8FB21935C0CD0019D689 /* UIScrollView+MJRefresh.m in Sources */ = {isa = PBXBuildFile; fileRef = 2D1D8FB11935C0CD0019D689 /* UIScrollView+MJRefresh.m */; };
+		2D1D8FB51935EABD0019D689 /* UIView+Extension.m in Sources */ = {isa = PBXBuildFile; fileRef = 2D1D8FB41935EABD0019D689 /* UIView+Extension.m */; };
+		2D1D8FB81935EACA0019D689 /* UIScrollView+Extension.m in Sources */ = {isa = PBXBuildFile; fileRef = 2D1D8FB71935EACA0019D689 /* UIScrollView+Extension.m */; };
 		2D9CAF6B192FAD750011F500 /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 2D9CAF6A192FAD750011F500 /* Foundation.framework */; };
 		2D9CAF6D192FAD750011F500 /* CoreGraphics.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 2D9CAF6C192FAD750011F500 /* CoreGraphics.framework */; };
 		2D9CAF6F192FAD750011F500 /* UIKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 2D9CAF6E192FAD750011F500 /* UIKit.framework */; };
@@ -45,6 +47,10 @@
 /* Begin PBXFileReference section */
 		2D1D8FB01935C0CD0019D689 /* UIScrollView+MJRefresh.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "UIScrollView+MJRefresh.h"; sourceTree = "<group>"; };
 		2D1D8FB11935C0CD0019D689 /* UIScrollView+MJRefresh.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "UIScrollView+MJRefresh.m"; sourceTree = "<group>"; };
+		2D1D8FB31935EABD0019D689 /* UIView+Extension.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "UIView+Extension.h"; sourceTree = "<group>"; };
+		2D1D8FB41935EABD0019D689 /* UIView+Extension.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "UIView+Extension.m"; sourceTree = "<group>"; };
+		2D1D8FB61935EACA0019D689 /* UIScrollView+Extension.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "UIScrollView+Extension.h"; sourceTree = "<group>"; };
+		2D1D8FB71935EACA0019D689 /* UIScrollView+Extension.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "UIScrollView+Extension.m"; sourceTree = "<group>"; };
 		2D9CAF67192FAD750011F500 /* MJRefreshExample.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = MJRefreshExample.app; sourceTree = BUILT_PRODUCTS_DIR; };
 		2D9CAF6A192FAD750011F500 /* Foundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Foundation.framework; path = System/Library/Frameworks/Foundation.framework; sourceTree = SDKROOT; };
 		2D9CAF6C192FAD750011F500 /* CoreGraphics.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreGraphics.framework; path = System/Library/Frameworks/CoreGraphics.framework; sourceTree = SDKROOT; };
@@ -235,6 +241,10 @@
 				2D9CAFBA192FAD9F0011F500 /* MJRefreshHeaderView.m */,
 				2D1D8FB01935C0CD0019D689 /* UIScrollView+MJRefresh.h */,
 				2D1D8FB11935C0CD0019D689 /* UIScrollView+MJRefresh.m */,
+				2D1D8FB31935EABD0019D689 /* UIView+Extension.h */,
+				2D1D8FB41935EABD0019D689 /* UIView+Extension.m */,
+				2D1D8FB61935EACA0019D689 /* UIScrollView+Extension.h */,
+				2D1D8FB71935EACA0019D689 /* UIScrollView+Extension.m */,
 			);
 			path = MJRefresh;
 			sourceTree = "<group>";
@@ -338,7 +348,9 @@
 			buildActionMask = 2147483647;
 			files = (
 				2D9CAFC5192FAD9F0011F500 /* MJRefreshFooterView.m in Sources */,
+				2D1D8FB81935EACA0019D689 /* UIScrollView+Extension.m in Sources */,
 				2D9CAFBE192FAD9F0011F500 /* MJTableViewController.m in Sources */,
+				2D1D8FB51935EABD0019D689 /* UIView+Extension.m in Sources */,
 				2D9CAFBD192FAD9F0011F500 /* MJSampleIndexViewController.m in Sources */,
 				2D9CAFBF192FAD9F0011F500 /* MJSampleIndex.m in Sources */,
 				2D9CAFC4192FAD9F0011F500 /* MJRefreshConst.m in Sources */,

BIN
MJRefreshExample/MJRefreshExample.xcodeproj/project.xcworkspace/xcuserdata/mj.xcuserdatad/UserInterfaceState.xcuserstate


+ 1 - 1
MJRefreshExample/MJRefreshExample/Classes/Controller/MJCollectionViewController.m

@@ -33,7 +33,7 @@ @implementation MJCollectionViewController
  */
 - (NSMutableArray *)fakeColors
 {
-    if (_fakeColors == nil) {
+    if (!_fakeColors) {
         self.fakeColors = [NSMutableArray array];
         
         for (int i = 0; i<5; i++) {

+ 1 - 1
MJRefreshExample/MJRefreshExample/Classes/Controller/MJTableViewController.m

@@ -32,7 +32,7 @@ @implementation MJTableViewController
  */
 - (NSMutableArray *)fakeData
 {
-    if (_fakeData == nil) {
+    if (!_fakeData) {
         self.fakeData = [NSMutableArray array];
         
         for (int i = 0; i<12; i++) {

+ 13 - 11
MJRefreshExample/MJRefreshExample/MJRefresh/MJRefreshBaseView.h

@@ -27,26 +27,28 @@ typedef enum {
  类的声明
  */
 @interface MJRefreshBaseView : UIView
-/**
- *  构造方法
- */
-- (instancetype)initWithScrollView:(UIScrollView *)scrollView;
-
-/**
- *  设置要显示的父控件
- */
-@property (nonatomic, weak) UIScrollView *scrollView;
+#pragma mark - 父控件
+@property (nonatomic, weak, readonly) UIScrollView *scrollView;
+@property (nonatomic, assign, readonly) UIEdgeInsets scrollViewOriginalInset;
 
 #pragma mark - 内部的控件
-@property (nonatomic, weak, readonly) UILabel *lastUpdateTimeLabel;
 @property (nonatomic, weak, readonly) UILabel *statusLabel;
 @property (nonatomic, weak, readonly) UIImageView *arrowImage;
 @property (nonatomic, weak, readonly) UIActivityIndicatorView *activityView;
-@property (nonatomic, assign, readonly) UIEdgeInsets scrollViewInitInset;
 
 #pragma mark - 回调
+/**
+ *  开始进入刷新状态的监听器
+ */
 @property (weak, nonatomic) id beginRefreshingTaget;
+/**
+ *  开始进入刷新状态的监听方法
+ */
 @property (assign, nonatomic) SEL beginRefreshingAction;
+/**
+ *  开始进入刷新状态就会调用
+ */
+@property (nonatomic, copy) void (^beginRefreshingCallback)();
 
 #pragma mark - 刷新相关
 /**

+ 101 - 126
MJRefreshExample/MJRefreshExample/MJRefresh/MJRefreshBaseView.m

@@ -8,10 +8,16 @@
 
 #import "MJRefreshBaseView.h"
 #import "MJRefreshConst.h"
+#import "UIView+Extension.h"
+#import "UIScrollView+Extension.h"
 #import <objc/message.h>
 
 @interface  MJRefreshBaseView()
-@property (assign, nonatomic) BOOL hasInitInset;
+{
+    __weak UILabel *_statusLabel;
+    __weak UIImageView *_arrowImage;
+    __weak UIActivityIndicatorView *_activityView;
+}
 /**
  交给子类去实现
  */
@@ -22,131 +28,114 @@ - (MJRefreshViewType)viewType;
 @end
 
 @implementation MJRefreshBaseView
-#pragma mark - 初始化方法
+#pragma mark - 控件初始化
 /**
- *  创建一个UILabel
- *
- *  @param size 字体大小
+ *  状态标签
  */
-- (UILabel *)labelWithFontSize:(CGFloat)size
+- (UILabel *)statusLabel
 {
-    UILabel *label = [[UILabel alloc] init];
-    label.autoresizingMask = UIViewAutoresizingFlexibleWidth;
-    label.font = [UIFont boldSystemFontOfSize:size];
-    label.textColor = MJRefreshLabelTextColor;
-    label.backgroundColor = [UIColor clearColor];
-    label.textAlignment = NSTextAlignmentCenter;
-    return label;
+    if (!_statusLabel) {
+        UILabel *statusLabel = [[UILabel alloc] init];
+        statusLabel.autoresizingMask = UIViewAutoresizingFlexibleWidth;
+        statusLabel.font = [UIFont boldSystemFontOfSize:13];
+        statusLabel.textColor = MJRefreshLabelTextColor;
+        statusLabel.backgroundColor = [UIColor clearColor];
+        statusLabel.textAlignment = NSTextAlignmentCenter;
+        [self addSubview:_statusLabel = statusLabel];
+    }
+    return _statusLabel;
 }
 
-- (instancetype)initWithScrollView:(UIScrollView *)scrollView
+/**
+ *  箭头图片
+ */
+- (UIImageView *)arrowImage
 {
-    if (self = [super init]) {
-        self.scrollView = scrollView;
+    if (!_arrowImage) {
+        UIImageView *arrowImage = [[UIImageView alloc] initWithImage:[UIImage imageNamed:MJRefreshSrcName(@"arrow.png")]];
+        arrowImage.autoresizingMask = UIViewAutoresizingFlexibleLeftMargin | UIViewAutoresizingFlexibleRightMargin;
+        [self addSubview:_arrowImage = arrowImage];
     }
-    return self;
+    return _arrowImage;
 }
 
-- (void)layoutSubviews
+/**
+ *  状态标签
+ */
+- (UIActivityIndicatorView *)activityView
 {
-    [super layoutSubviews];
-    
-    if (!self.hasInitInset) { // 记录scrollView刚开始的contentInset
-        _scrollViewInitInset = self.scrollView.contentInset;
-        
-        // 监听
-        [self observeValueForKeyPath:MJRefreshContentSize ofObject:nil change:nil context:nil];
-        
-        self.hasInitInset = YES;
-        
-        // 进入刷新状态
-        if (self.state == MJRefreshStateWillRefreshing) {
-            [self setState:MJRefreshStateRefreshing];
-        }
+    if (!_activityView) {
+        UIActivityIndicatorView *activityView = [[UIActivityIndicatorView alloc] initWithActivityIndicatorStyle:UIActivityIndicatorViewStyleGray];
+        activityView.bounds = self.arrowImage.bounds;
+        activityView.autoresizingMask = self.arrowImage.autoresizingMask;
+        [self addSubview:_activityView = activityView];
     }
+    return _activityView;
 }
 
-/**
- *  构造方法
- */
+#pragma mark - 初始化方法
 - (instancetype)initWithFrame:(CGRect)frame {
+    frame.size.height = MJRefreshViewHeight;
     if (self = [super initWithFrame:frame]) {
         // 1.自己的属性
         self.autoresizingMask = UIViewAutoresizingFlexibleWidth;
         self.backgroundColor = [UIColor clearColor];
         
-        // 2.时间标签
-        [self addSubview:_lastUpdateTimeLabel = [self labelWithFontSize:12]];
-        
-        // 3.状态标签
-        [self addSubview:_statusLabel = [self labelWithFontSize:13]];
-        
-        // 4.箭头图片
-        UIImageView *arrowImage = [[UIImageView alloc] initWithImage:[UIImage imageNamed:MJRefreshSrcName(@"arrow.png")]];
-        arrowImage.autoresizingMask = UIViewAutoresizingFlexibleLeftMargin | UIViewAutoresizingFlexibleRightMargin;
-        [self addSubview:_arrowImage = arrowImage];
-        
-        // 5.指示器
-        UIActivityIndicatorView *activityView = [[UIActivityIndicatorView alloc] initWithActivityIndicatorStyle:UIActivityIndicatorViewStyleGray];
-        activityView.bounds = arrowImage.bounds;
-        activityView.autoresizingMask = arrowImage.autoresizingMask;
-        [self addSubview:_activityView = activityView];
-        
-        // 6.设置默认状态
+        // 2.设置默认状态
         self.state = MJRefreshStateNormal;
     }
     return self;
 }
 
-/**
- *  设置frame
- */
-- (void)setFrame:(CGRect)frame
+- (void)layoutSubviews
 {
-    frame.size.height = MJRefreshViewHeight;
-    [super setFrame:frame];
-    
-    CGFloat w = frame.size.width;
-    CGFloat h = frame.size.height;
-    if (w == 0 || self.arrowImage.center.y == h * 0.5) return;
-    
-    CGFloat statusX = 0;
-    CGFloat statusY = 5;
-    CGFloat statusHeight = 20;
-    CGFloat statusWidth = w;
-    // 1.状态标签
-    self.statusLabel.frame = CGRectMake(statusX, statusY, statusWidth, statusHeight);
-    
-    // 2.时间标签
-    CGFloat lastUpdateY = statusY + statusHeight + 5;
-    self.lastUpdateTimeLabel.frame = CGRectMake(statusX, lastUpdateY, statusWidth, statusHeight);
+    [super layoutSubviews];
     
-    // 3.箭头
-    CGFloat arrowX = w * 0.5 - 100;
-    self.arrowImage.center = CGPointMake(arrowX, h * 0.5);
+    // 1.箭头
+    CGFloat arrowX = self.width * 0.5 - 100;
+    self.arrowImage.center = CGPointMake(arrowX, self.height * 0.5);
     
-    // 4.指示器
-    self.activityView.center = _arrowImage.center;
+    // 2.指示器
+    self.activityView.center = self.arrowImage.center;
 }
 
-- (void)setBounds:(CGRect)bounds
+#pragma mark - 显示到屏幕上
+- (void)drawRect:(CGRect)rect
 {
-    bounds.size.height = MJRefreshViewHeight;
-    [super setBounds:bounds];
+    if (self.state == MJRefreshStateWillRefreshing) {
+        self.state = MJRefreshStateRefreshing;
+    }
 }
 
-#pragma mark - UIScrollView相关
-/**
- *  设置UIScrollView
-*/
-- (void)setScrollView:(UIScrollView *)scrollView
+#pragma mark - 刷新相关
+#pragma mark 是否正在刷新
+- (BOOL)isRefreshing
 {
-    [scrollView addSubview:self];
-    // 设置scrollView
-    _scrollView = scrollView;
+    return MJRefreshStateRefreshing == self.state;
 }
 
-#pragma mark 监听UIScrollView的contentOffset属性
+#pragma mark 开始刷新
+- (void)beginRefreshing
+{
+    if (self.window) {
+        self.state = MJRefreshStateRefreshing;
+    } else {
+#warning 不能调用set方法
+        _state = MJRefreshStateWillRefreshing;
+    }
+}
+
+#pragma mark 结束刷新
+- (void)endRefreshing
+{
+    double delayInSeconds = 0.3;
+    dispatch_time_t popTime = dispatch_time(DISPATCH_TIME_NOW, (int64_t)(delayInSeconds * NSEC_PER_SEC));
+    dispatch_after(popTime, dispatch_get_main_queue(), ^(void){
+        self.state = MJRefreshStateNormal;
+    });
+}
+
+#pragma mark - 监听UIScrollView的contentOffset属性
 - (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context
 {    
     if (![MJRefreshContentOffset isEqualToString:keyPath]) return;
@@ -160,7 +149,7 @@ - (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(N
     if (offsetY <= validY) return;
     
     if (self.scrollView.isDragging) {
-        CGFloat validOffsetY = validY + MJRefreshViewHeight;
+        CGFloat validOffsetY = validY + self.frame.size.height;
         if (self.state == MJRefreshStatePulling && offsetY <= validOffsetY) {
             // 转为普通状态
             self.state = MJRefreshStateNormal;
@@ -176,12 +165,12 @@ - (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(N
     }
 }
 
-#pragma mark 设置状态
+#pragma mark - 设置状态
 - (void)setState:(MJRefreshState)state
 {
     if (self.state != MJRefreshStateRefreshing) {
         // 存储当前的contentInset
-        _scrollViewInitInset = self.scrollView.contentInset;
+        _scrollViewOriginalInset = self.scrollView.contentInset;
     }
     
     // 1.一样的就直接返回
@@ -190,17 +179,13 @@ - (void)setState:(MJRefreshState)state
     // 2.根据状态执行不同的操作
     switch (state) {
 		case MJRefreshStateNormal: // 普通状态
+        {
             // 显示箭头
             self.arrowImage.hidden = NO;
             // 停止转圈圈
-			[self.activityView stopAnimating];
-            
-            // 说明是刚刷新完毕 回到 普通状态的
-            if (MJRefreshStateRefreshing == self.state) {
-                
-            }
-            
+            [self.activityView stopAnimating];
 			break;
+        }
             
         case MJRefreshStatePulling:
             break;
@@ -212,9 +197,14 @@ - (void)setState:(MJRefreshState)state
 			self.arrowImage.hidden = YES;
             self.arrowImage.transform = CGAffineTransformIdentity;
             
+            // 回调
             if ([self.beginRefreshingTaget respondsToSelector:self.beginRefreshingAction]) {
                 objc_msgSend(self.beginRefreshingTaget, self.beginRefreshingAction, self);
             }
+            
+            if (self.beginRefreshingCallback) {
+                self.beginRefreshingCallback();
+            }
 			break;
         default:
             break;
@@ -224,43 +214,28 @@ - (void)setState:(MJRefreshState)state
     _state = state;
 }
 
-#pragma mark - 状态相关
-#pragma mark 是否正在刷新
-- (BOOL)isRefreshing
-{
-    return MJRefreshStateRefreshing == self.state;
-}
-#pragma mark 开始刷新
-- (void)beginRefreshing
-{
-    if (self.window) {
-        self.state = MJRefreshStateRefreshing;
-    } else {
-        _state = MJRefreshStateWillRefreshing;
-    }
-}
-#pragma mark 结束刷新
-- (void)endRefreshing
-{
-    double delayInSeconds = 0.3;
-    dispatch_time_t popTime = dispatch_time(DISPATCH_TIME_NOW, (int64_t)(delayInSeconds * NSEC_PER_SEC));
-    dispatch_after(popTime, dispatch_get_main_queue(), ^(void){
-        self.state = MJRefreshStateNormal;
-    });
-}
-
 #pragma mark - 随便实现
 - (CGFloat)validY { return 0;}
 - (MJRefreshViewType)viewType {return MJRefreshViewTypeHeader;}
 
 - (void)willMoveToSuperview:(UIView *)newSuperview
 {
+    [super willMoveToSuperview:newSuperview];
+    
     if (self.superview) { // 旧的父控件
         [self.superview removeObserver:self forKeyPath:MJRefreshContentOffset context:nil];
     }
     
     if (newSuperview) { // 新的父控件
         [newSuperview addObserver:self forKeyPath:MJRefreshContentOffset options:NSKeyValueObservingOptionNew context:nil];
+        
+        // 设置宽度
+        self.width = newSuperview.width;
+        
+        // 记录UIScrollView
+        _scrollView = (UIScrollView *)newSuperview;
+        // 记录UIScrollView最开始的contentInset
+        _scrollViewOriginalInset = _scrollView.contentInset;
     }
 }
 

+ 4 - 2
MJRefreshExample/MJRefreshExample/MJRefresh/MJRefreshConst.h

@@ -12,11 +12,13 @@
 #define MJLog(...)
 #endif
 
+#define MJColor(r, g, b) [UIColor colorWithRed:(r)/255.0 green:(g)/255.0 blue:(b)/255.0 alpha:1.0]
 // 文字颜色
-#define MJRefreshLabelTextColor [UIColor colorWithRed:150/255.0 green:150/255.0 blue:150/255.0 alpha:1.0]
+#define MJRefreshLabelTextColor MJColor(150, 150, 150)
 
 extern const CGFloat MJRefreshViewHeight;
-extern const CGFloat MJRefreshAnimationDuration;
+extern const CGFloat MJRefreshFastAnimationDuration;
+extern const CGFloat MJRefreshSlowAnimationDuration;
 
 extern NSString *const MJRefreshBundleName;
 #define MJRefreshSrcName(file) [MJRefreshBundleName stringByAppendingPathComponent:file]

+ 2 - 1
MJRefreshExample/MJRefreshExample/MJRefresh/MJRefreshConst.m

@@ -7,7 +7,8 @@
 //
 
 const CGFloat MJRefreshViewHeight = 64.0;
-const CGFloat MJRefreshAnimationDuration = 0.25;
+const CGFloat MJRefreshFastAnimationDuration = 0.25;
+const CGFloat MJRefreshSlowAnimationDuration = 0.4;
 
 NSString *const MJRefreshBundleName = @"MJRefresh.bundle";
 

+ 0 - 23
MJRefreshExample/MJRefreshExample/MJRefresh/MJRefreshFooterView.h

@@ -7,30 +7,7 @@
 //  上拉加载更多
 
 #import "MJRefreshBaseView.h"
-@class MJRefreshFooterView;
-
-/**
- 代理的协议定义
- */
-@protocol MJRefreshFooterViewDelegate <NSObject>
-@optional
-/**
- *  开始进入刷新状态就会调用
- *
- *  @param refreshFooterView 刷新控件
- */
-- (void)refreshFooterViewBeginRefreshing:(MJRefreshFooterView *)refreshFooterView;
-@end
 
 @interface MJRefreshFooterView : MJRefreshBaseView
 + (instancetype)footer;
-/**
- *  代理
- */
-@property (weak, nonatomic) id<MJRefreshFooterViewDelegate> delegate;
-
-/**
- *  开始进入刷新状态就会调用
- */
-@property (nonatomic, copy) void (^beginRefreshingCallback)(MJRefreshFooterView *refreshFooterView);
 @end

+ 32 - 58
MJRefreshExample/MJRefreshExample/MJRefresh/MJRefreshFooterView.m

@@ -8,6 +8,8 @@
 
 #import "MJRefreshFooterView.h"
 #import "MJRefreshConst.h"
+#import "UIView+Extension.h"
+#import "UIScrollView+Extension.h"
 
 @interface MJRefreshFooterView()
 @property (assign, nonatomic) int lastRefreshCount;
@@ -20,24 +22,11 @@ + (instancetype)footer
     return [[MJRefreshFooterView alloc] init];
 }
 
-#pragma mark - 初始化
-- (instancetype)initWithFrame:(CGRect)frame {
-    if (self = [super initWithFrame: frame]) {
-        // 移除刷新时间
-		[self.lastUpdateTimeLabel removeFromSuperview];
-    }
-    return self;
-}
-
-- (void)setFrame:(CGRect)frame
+- (void)layoutSubviews
 {
-    [super setFrame:frame];
+    [super layoutSubviews];
     
-    CGFloat h = frame.size.height;
-    if (self.statusLabel.center.y != h * 0.5) {
-        CGFloat w = self.frame.size.width;
-        self.statusLabel.center = CGPointMake(w * 0.5, h * 0.5);
-    }
+    self.statusLabel.frame = self.bounds;
 }
 
 - (void)willMoveToSuperview:(UIView *)newSuperview
@@ -49,19 +38,23 @@ - (void)willMoveToSuperview:(UIView *)newSuperview
     }
     
     if (newSuperview) { // 新的父控件
+        // 监听
         [newSuperview addObserver:self forKeyPath:MJRefreshContentSize options:NSKeyValueObservingOptionNew context:nil];
+        
+        // 重新调整frame
+        [self adjustFrame];
     }
 }
 
-#pragma mark - UIScrollView相关
-#pragma mark 重写设置ScrollView
-- (void)setScrollView:(UIScrollView *)scrollView
+#pragma mark 重写调整frame
+- (void)adjustFrame
 {
-    // 父类的方法
-    [super setScrollView:scrollView];
-    
-    // 重新调整frame
-    [self adjustFrame];
+    // 内容的高度
+    CGFloat contentHeight = self.scrollView.contentSizeHeight;
+    // 表格的高度
+    CGFloat scrollHeight = self.scrollView.height - self.scrollViewOriginalInset.top - self.scrollViewOriginalInset.bottom;
+    // 设置位置和尺寸
+    self.y = MAX(contentHeight, scrollHeight);
 }
 
 #pragma mark 监听UIScrollView的属性
@@ -76,18 +69,6 @@ - (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(N
     }
 }
 
-#pragma mark 重写调整frame
-- (void)adjustFrame
-{
-    // 内容的高度
-    CGFloat contentHeight = self.scrollView.contentSize.height;
-    // 表格的高度
-    CGFloat scrollHeight = self.scrollView.frame.size.height - self.scrollViewInitInset.top - self.scrollViewInitInset.bottom;
-    CGFloat y = MAX(contentHeight, scrollHeight);
-    // 设置边框
-    self.frame = CGRectMake(0, y, self.scrollView.frame.size.width, MJRefreshViewHeight);
-}
-
 #pragma mark - 状态相关
 #pragma mark 设置状态
 - (void)setState:(MJRefreshState)state
@@ -103,10 +84,10 @@ - (void)setState:(MJRefreshState)state
         {
             self.statusLabel.text = MJRefreshFooterReleaseToRefresh;
             
-            [UIView animateWithDuration:MJRefreshAnimationDuration animations:^{
+            [UIView animateWithDuration:MJRefreshFastAnimationDuration animations:^{
                 self.arrowImage.transform = CGAffineTransformIdentity;
                 UIEdgeInsets inset = self.scrollView.contentInset;
-                inset.bottom = self.scrollViewInitInset.bottom;
+                inset.bottom = self.scrollViewOriginalInset.bottom;
                 self.scrollView.contentInset = inset;
             }];
 			break;
@@ -117,7 +98,7 @@ - (void)setState:(MJRefreshState)state
             self.statusLabel.text = MJRefreshFooterPullToRefresh;
             
             // 刚刷新完毕
-            CGFloat animDuration = MJRefreshAnimationDuration;
+            CGFloat animDuration = MJRefreshSlowAnimationDuration;
             CGFloat deltaH = [self contentBreakView];
             CGPoint tempOffset;
             
@@ -128,12 +109,15 @@ - (void)setState:(MJRefreshState)state
             }
             
             [UIView animateWithDuration:animDuration animations:^{
-                self.arrowImage.transform = CGAffineTransformMakeRotation(M_PI);
                 UIEdgeInsets inset = self.scrollView.contentInset;
-                inset.bottom = self.scrollViewInitInset.bottom;
+                inset.bottom = self.scrollViewOriginalInset.bottom;
                 self.scrollView.contentInset = inset;
             }];
             
+            [UIView animateWithDuration:animDuration ? MJRefreshFastAnimationDuration : animDuration animations:^{
+                self.arrowImage.transform = CGAffineTransformMakeRotation(M_PI);
+            }];
+            
             if (animDuration == 0) {
                 self.scrollView.contentOffset = tempOffset;
             }
@@ -144,12 +128,12 @@ - (void)setState:(MJRefreshState)state
         {
             // 记录刷新前的数量
             self.lastRefreshCount = [self totalDataCountInScrollView];
-            
             self.statusLabel.text = MJRefreshFooterRefreshing;
-            self.arrowImage.transform = CGAffineTransformMakeRotation(M_PI);
-            [UIView animateWithDuration:MJRefreshAnimationDuration animations:^{
+            
+            [UIView animateWithDuration:MJRefreshFastAnimationDuration animations:^{
+                self.arrowImage.transform = CGAffineTransformMakeRotation(M_PI);
                 UIEdgeInsets inset = self.scrollView.contentInset;
-                CGFloat bottom = MJRefreshViewHeight + self.scrollViewInitInset.bottom;
+                CGFloat bottom = self.frame.size.height + self.scrollViewOriginalInset.bottom;
                 CGFloat deltaH = [self contentBreakView];
                 if (deltaH < 0) { // 如果内容高度小于view的高度
                     bottom -= deltaH;
@@ -157,16 +141,6 @@ - (void)setState:(MJRefreshState)state
                 inset.bottom = bottom;
                 self.scrollView.contentInset = inset;
             }];
-            
-            // 通知代理
-            if ([self.delegate respondsToSelector:@selector(refreshFooterViewBeginRefreshing:)]) {
-                [self.delegate refreshFooterViewBeginRefreshing:self];
-            }
-            
-            // 回调
-            if (self.beginRefreshingCallback) {
-                self.beginRefreshingCallback(self);
-            }
 			break;
         }
             
@@ -178,7 +152,7 @@ - (void)setState:(MJRefreshState)state
 #pragma mark 获得scrollView的内容 超出 view 的高度
 - (CGFloat)contentBreakView
 {
-    CGFloat h = self.scrollView.frame.size.height - self.scrollViewInitInset.bottom - self.scrollViewInitInset.top;
+    CGFloat h = self.scrollView.frame.size.height - self.scrollViewOriginalInset.bottom - self.scrollViewOriginalInset.top;
     return self.scrollView.contentSize.height - h;
 }
 
@@ -188,9 +162,9 @@ - (CGFloat)validY
 {
     CGFloat deltaH = [self contentBreakView];
     if (deltaH > 0) {
-        return deltaH - self.scrollViewInitInset.top;
+        return deltaH - self.scrollViewOriginalInset.top;
     } else {
-        return - self.scrollViewInitInset.top;
+        return - self.scrollViewOriginalInset.top;
     }
 }
 

+ 0 - 23
MJRefreshExample/MJRefreshExample/MJRefresh/MJRefreshHeaderView.h

@@ -7,30 +7,7 @@
 //  下拉刷新
 
 #import "MJRefreshBaseView.h"
-@class MJRefreshHeaderView;
-
-/**
- 代理的协议定义
- */
-@protocol MJRefreshHeaderViewDelegate <NSObject>
-@optional
-/**
- *  开始进入刷新状态就会调用
- *
- *  @param refreshHeaderView 刷新控件
- */
-- (void)refreshHeaderViewBeginRefreshing:(MJRefreshHeaderView *)refreshHeaderView;
-@end
 
 @interface MJRefreshHeaderView : MJRefreshBaseView
 + (instancetype)header;
-/**
- *  代理
- */
-@property (weak, nonatomic) id<MJRefreshHeaderViewDelegate> delegate;
-
-/**
- *  开始进入刷新状态就会调用
- */
-@property (nonatomic, copy) void (^beginRefreshingCallback)(MJRefreshHeaderView *refreshHeaderView);
 @end

+ 57 - 26
MJRefreshExample/MJRefreshExample/MJRefresh/MJRefreshHeaderView.m

@@ -8,30 +8,68 @@
 
 #import "MJRefreshConst.h"
 #import "MJRefreshHeaderView.h"
+#import "UIView+Extension.h"
+#import "UIScrollView+Extension.h"
 
 @interface MJRefreshHeaderView()
 // 最后的更新时间
 @property (nonatomic, strong) NSDate *lastUpdateTime;
+@property (nonatomic, weak) UILabel *lastUpdateTimeLabel;
 @end
 
 @implementation MJRefreshHeaderView
+#pragma mark - 控件初始化
+/**
+ *  时间标签
+ */
+- (UILabel *)lastUpdateTimeLabel
+{
+    if (!_lastUpdateTimeLabel) {
+        // 1.创建控件
+        UILabel *lastUpdateTimeLabel = [[UILabel alloc] init];
+        lastUpdateTimeLabel.autoresizingMask = UIViewAutoresizingFlexibleWidth;
+        lastUpdateTimeLabel.font = [UIFont boldSystemFontOfSize:12];
+        lastUpdateTimeLabel.textColor = MJRefreshLabelTextColor;
+        lastUpdateTimeLabel.backgroundColor = [UIColor clearColor];
+        lastUpdateTimeLabel.textAlignment = NSTextAlignmentCenter;
+        [self addSubview:_lastUpdateTimeLabel = lastUpdateTimeLabel];
+        
+        // 2.加载时间
+        self.lastUpdateTime = [[NSUserDefaults standardUserDefaults] objectForKey:MJRefreshHeaderTimeKey];
+    }
+    return _lastUpdateTimeLabel;
+}
 
 + (instancetype)header
 {
     return [[MJRefreshHeaderView alloc] init];
 }
 
-#pragma mark - UIScrollView相关
-#pragma mark 重写设置ScrollView
-- (void)setScrollView:(UIScrollView *)scrollView
+- (void)layoutSubviews
 {
-    [super setScrollView:scrollView];
+    [super layoutSubviews];
+    
+    CGFloat statusX = 0;
+    CGFloat statusY = 0;
+    CGFloat statusHeight = self.height * 0.5;
+    CGFloat statusWidth = self.width;
+    // 1.状态标签
+    self.statusLabel.frame = CGRectMake(statusX, statusY, statusWidth, statusHeight);
     
-    // 1.设置边框
-    self.frame = CGRectMake(0, - MJRefreshViewHeight, scrollView.frame.size.width, MJRefreshViewHeight);
+    // 2.时间标签
+    CGFloat lastUpdateY = statusHeight;
+    CGFloat lastUpdateX = 0;
+    CGFloat lastUpdateHeight = statusHeight;
+    CGFloat lastUpdateWidth = statusWidth;
+    self.lastUpdateTimeLabel.frame = CGRectMake(lastUpdateX, lastUpdateY, lastUpdateWidth, lastUpdateHeight);
+}
+
+- (void)willMoveToSuperview:(UIView *)newSuperview
+{
+    [super willMoveToSuperview:newSuperview];
     
-    // 2.加载时间
-    self.lastUpdateTime = [[NSUserDefaults standardUserDefaults] objectForKey:MJRefreshHeaderTimeKey];
+    // 设置自己的位置和尺寸
+    self.y = - self.height;
 }
 
 #pragma mark - 状态相关
@@ -93,10 +131,10 @@ - (void)setState:(MJRefreshState)state
             // 设置文字
             self.statusLabel.text = MJRefreshHeaderReleaseToRefresh;
             // 执行动画
-            [UIView animateWithDuration:MJRefreshAnimationDuration animations:^{
+            [UIView animateWithDuration:MJRefreshFastAnimationDuration animations:^{
                 self.arrowImage.transform = CGAffineTransformMakeRotation(M_PI);
                 UIEdgeInsets inset = self.scrollView.contentInset;
-                inset.top = self.scrollViewInitInset.top;
+                inset.top = self.scrollViewOriginalInset.top;
                 self.scrollView.contentInset = inset;
             }];
 			break;
@@ -107,10 +145,13 @@ - (void)setState:(MJRefreshState)state
             // 设置文字
 			self.statusLabel.text = MJRefreshHeaderPullToRefresh;
             // 执行动画
-            [UIView animateWithDuration:MJRefreshAnimationDuration animations:^{
+            [UIView animateWithDuration:MJRefreshFastAnimationDuration animations:^{
                 self.arrowImage.transform = CGAffineTransformIdentity;
+            }];
+            
+            [UIView animateWithDuration:MJRefreshSlowAnimationDuration animations:^{
                 UIEdgeInsets inset = self.scrollView.contentInset;
-                inset.top = self.scrollViewInitInset.top;
+                inset.top = self.scrollViewOriginalInset.top;
                 self.scrollView.contentInset = inset;
             }];
             
@@ -127,25 +168,15 @@ - (void)setState:(MJRefreshState)state
             // 设置文字
             self.statusLabel.text = MJRefreshHeaderRefreshing;
             // 执行动画
-            [UIView animateWithDuration:MJRefreshAnimationDuration animations:^{
+            [UIView animateWithDuration:MJRefreshFastAnimationDuration animations:^{
                 self.arrowImage.transform = CGAffineTransformIdentity;
                 // 1.增加65的滚动区域
                 UIEdgeInsets inset = self.scrollView.contentInset;
-                inset.top = self.scrollViewInitInset.top + MJRefreshViewHeight;
+                inset.top = self.scrollViewOriginalInset.top + MJRefreshViewHeight;
                 self.scrollView.contentInset = inset;
                 // 2.设置滚动位置
-                self.scrollView.contentOffset = CGPointMake(0, - self.scrollViewInitInset.top - MJRefreshViewHeight);
+                self.scrollView.contentOffset = CGPointMake(0, - self.scrollViewOriginalInset.top - MJRefreshViewHeight);
             }];
-            
-            // 通知代理
-            if ([self.delegate respondsToSelector:@selector(refreshHeaderViewBeginRefreshing:)]) {
-                [self.delegate refreshHeaderViewBeginRefreshing:self];
-            }
-            
-            // 回调
-            if (self.beginRefreshingCallback) {
-                self.beginRefreshingCallback(self);
-            }
 			break;
         }
             
@@ -158,7 +189,7 @@ - (void)setState:(MJRefreshState)state
 // 合理的Y值(刚好看到下拉刷新控件时的contentOffset.y,取相反数)
 - (CGFloat)validY
 {
-    return self.scrollViewInitInset.top;
+    return self.scrollViewOriginalInset.top;
 }
 
 // view的类型

+ 22 - 0
MJRefreshExample/MJRefreshExample/MJRefresh/UIScrollView+Extension.h

@@ -0,0 +1,22 @@
+//
+//  UIScrollView+Extension.h
+//  MJRefreshExample
+//
+//  Created by MJ Lee on 14-5-28.
+//  Copyright (c) 2014年 itcast. All rights reserved.
+//
+
+#import <UIKit/UIKit.h>
+
+@interface UIScrollView (Extension)
+@property (assign, nonatomic) CGFloat contentInsetTop;
+@property (assign, nonatomic) CGFloat contentInsetBottom;
+@property (assign, nonatomic) CGFloat contentInsetLeft;
+@property (assign, nonatomic) CGFloat contentInsetRight;
+
+@property (assign, nonatomic) CGFloat contentOffsetX;
+@property (assign, nonatomic) CGFloat contentOffsetY;
+
+@property (assign, nonatomic) CGFloat contentSizeWidth;
+@property (assign, nonatomic) CGFloat contentSizeHeight;
+@end

+ 107 - 0
MJRefreshExample/MJRefreshExample/MJRefresh/UIScrollView+Extension.m

@@ -0,0 +1,107 @@
+//
+//  UIScrollView+Extension.m
+//  MJRefreshExample
+//
+//  Created by MJ Lee on 14-5-28.
+//  Copyright (c) 2014年 itcast. All rights reserved.
+//
+
+#import "UIScrollView+Extension.h"
+
+@implementation UIScrollView (Extension)
+- (void)setContentInsetTop:(CGFloat)contentInsetTop
+{
+    UIEdgeInsets inset = self.contentInset;
+    inset.top = contentInsetTop;
+    self.contentInset = inset;
+}
+
+- (CGFloat)contentInsetTop
+{
+    return self.contentInset.top;
+}
+
+- (void)setContentInsetBottom:(CGFloat)contentInsetBottom
+{
+    UIEdgeInsets inset = self.contentInset;
+    inset.bottom = contentInsetBottom;
+    self.contentInset = inset;
+}
+
+- (CGFloat)contentInsetBottom
+{
+    return self.contentInset.bottom;
+}
+
+- (void)setContentInsetLeft:(CGFloat)contentInsetLeft
+{
+    UIEdgeInsets inset = self.contentInset;
+    inset.left = contentInsetLeft;
+    self.contentInset = inset;
+}
+
+- (CGFloat)contentInsetLeft
+{
+    return self.contentInset.left;
+}
+
+- (void)setContentInsetRight:(CGFloat)contentInsetRight
+{
+    UIEdgeInsets inset = self.contentInset;
+    inset.right = contentInsetRight;
+    self.contentInset = inset;
+}
+
+- (CGFloat)contentInsetRight
+{
+    return self.contentInset.right;
+}
+
+- (void)setContentOffsetX:(CGFloat)contentOffsetX
+{
+    CGPoint offset = self.contentOffset;
+    offset.x = contentOffsetX;
+    self.contentOffset = offset;
+}
+
+- (CGFloat)contentOffsetX
+{
+    return self.contentOffset.x;
+}
+
+- (void)setContentOffsetY:(CGFloat)contentOffsetY
+{
+    CGPoint offset = self.contentOffset;
+    offset.y = contentOffsetY;
+    self.contentOffset = offset;
+}
+
+- (CGFloat)contentOffsetY
+{
+    return self.contentOffset.y;
+}
+
+- (void)setContentSizeWidth:(CGFloat)contentSizeWidth
+{
+    CGSize size = self.contentSize;
+    size.width = contentSizeWidth;
+    self.contentSize = size;
+}
+
+- (CGFloat)contentSizeWidth
+{
+    return self.contentSize.width;
+}
+
+- (void)setContentSizeHeight:(CGFloat)contentSizeHeight
+{
+    CGSize size = self.contentSize;
+    size.height = contentSizeHeight;
+    self.contentSize = size;
+}
+
+- (CGFloat)contentSizeHeight
+{
+    return self.contentSize.height;
+}
+@end

+ 6 - 14
MJRefreshExample/MJRefreshExample/MJRefresh/UIScrollView+MJRefresh.m

@@ -58,16 +58,12 @@ - (void)addHeaderWithCallback:(void (^)())callback
     // 1.创建新的header
     if (!self.header) {
         MJRefreshHeaderView *header = [MJRefreshHeaderView header];
-        header.scrollView = self;
+        [self addSubview:header];
         self.header = header;
     }
     
     // 2.设置block回调
-    self.header.beginRefreshingCallback = ^(MJRefreshHeaderView *refreshHeaderView){
-        if (callback) {
-            callback();
-        }
-    };
+    self.header.beginRefreshingCallback = callback;
 }
 
 /**
@@ -81,7 +77,7 @@ - (void)addHeaderWithTarget:(id)target action:(SEL)action
     // 1.创建新的header
     if (!self.header) {
         MJRefreshHeaderView *header = [MJRefreshHeaderView header];
-        header.scrollView = self;
+        [self addSubview:header];
         self.header = header;
     }
     
@@ -139,16 +135,12 @@ - (void)addFooterWithCallback:(void (^)())callback
     // 1.创建新的footer
     if (!self.footer) {
         MJRefreshFooterView *footer = [MJRefreshFooterView footer];
-        footer.scrollView = self;
+        [self addSubview:footer];
         self.footer = footer;
     }
     
     // 2.设置block回调
-    self.footer.beginRefreshingCallback = ^(MJRefreshFooterView *refreshFooterView){
-        if (callback) {
-            callback();
-        }
-    };
+    self.footer.beginRefreshingCallback = callback;
 }
 
 /**
@@ -162,7 +154,7 @@ - (void)addFooterWithTarget:(id)target action:(SEL)action
     // 1.创建新的footer
     if (!self.footer) {
         MJRefreshFooterView *footer = [MJRefreshFooterView footer];
-        footer.scrollView = self;
+        [self addSubview:footer];
         self.footer = footer;
     }
     

+ 18 - 0
MJRefreshExample/MJRefreshExample/MJRefresh/UIView+Extension.h

@@ -0,0 +1,18 @@
+//
+//  UIView+Extension.h
+//  MJRefreshExample
+//
+//  Created by MJ Lee on 14-5-28.
+//  Copyright (c) 2014年 itcast. All rights reserved.
+//
+
+#import <UIKit/UIKit.h>
+
+@interface UIView (Extension)
+@property (assign, nonatomic) CGFloat x;
+@property (assign, nonatomic) CGFloat y;
+@property (assign, nonatomic) CGFloat width;
+@property (assign, nonatomic) CGFloat height;
+@property (assign, nonatomic) CGSize size;
+@property (assign, nonatomic) CGPoint origin;
+@end

+ 83 - 0
MJRefreshExample/MJRefreshExample/MJRefresh/UIView+Extension.m

@@ -0,0 +1,83 @@
+//
+//  UIView+Extension.m
+//  MJRefreshExample
+//
+//  Created by MJ Lee on 14-5-28.
+//  Copyright (c) 2014年 itcast. All rights reserved.
+//
+
+#import "UIView+Extension.h"
+
+@implementation UIView (Extension)
+- (void)setX:(CGFloat)x
+{
+    CGRect frame = self.frame;
+    frame.origin.x = x;
+    self.frame = frame;
+}
+
+- (CGFloat)x
+{
+    return self.frame.origin.x;
+}
+
+- (void)setY:(CGFloat)y
+{
+    CGRect frame = self.frame;
+    frame.origin.y = y;
+    self.frame = frame;
+}
+
+- (CGFloat)y
+{
+    return self.frame.origin.y;
+}
+
+- (void)setWidth:(CGFloat)width
+{
+    CGRect frame = self.frame;
+    frame.size.width = width;
+    self.frame = frame;
+}
+
+- (CGFloat)width
+{
+    return self.frame.size.width;
+}
+
+- (void)setHeight:(CGFloat)height
+{
+    CGRect frame = self.frame;
+    frame.size.height = height;
+    self.frame = frame;
+}
+
+- (CGFloat)height
+{
+    return self.frame.size.height;
+}
+
+- (void)setSize:(CGSize)size
+{
+    CGRect frame = self.frame;
+    frame.size = size;
+    self.frame = frame;
+}
+
+- (CGSize)size
+{
+    return self.frame.size;
+}
+
+- (void)setOrigin:(CGPoint)origin
+{
+    CGRect frame = self.frame;
+    frame.origin = origin;
+    self.frame = frame;
+}
+
+- (CGPoint)origin
+{
+    return self.frame.origin;
+}
+@end