下拉刷新对象RefreshObject
效果
说明
1. 分离了动画实现与刷新逻辑
2. 你可以根据自己的需要,设计自己的动画效果,你的动画只需要继承协议,实现协议里面的方法即可
3. 本设计方案是用的组件方式,代码复用率很高,灵活性很强
源码
https://github.com/YouXianMing/RefreshObject
// // RefreshObjectAnimationProtocal.h // TableViewRefresh // // Created by YouXianMing on 15/6/25. // Copyright (c) 2015年 YouXianMing. All rights reserved. // #import <Foundation/Foundation.h> @protocol RefreshObjectAnimationProtocal <NSObject> @required - (void)animationWithPercent:(CGFloat)percent; - (void)startRefreshAnimation; - (void)endRefreshAnimation; @end
// // RefreshObject.h // UIScrollView // // Created by YouXianMing on 15/6/24. // Copyright (c) 2015年 YouXianMing. All rights reserved. // #import <Foundation/Foundation.h> #import <UIKit/UIKit.h> @class RefreshObject; typedef enum : NSUInteger { NORMAL_STATE, // 正常状态 REFRESH_STATE, // 刷新状态 } ERefreshState; @protocol RefreshObjectDelegate <NSObject> @required /** * 开始刷新 * * @param refreshObject */ - (void)startRefreshing:(RefreshObject *)refreshObject; /** * 结束刷新 * * @param refreshObject */ - (void)endRefresh:(RefreshObject *)refreshObject; - (void)moving:(RefreshObject *)refreshObject offset:(CGFloat)offset percent:(CGFloat)percent; @end @interface RefreshObject : NSObject /** * 代理 */ @property (nonatomic, weak) id <RefreshObjectDelegate> delegate; /** * 当前状态 */ @property (nonatomic, readonly) ERefreshState state; @property (nonatomic) CGFloat height; @property (nonatomic, weak) UIScrollView *scrollView; /** * === 子类可以重写该方法实现新的刷新效果 === * * 开始刷新 */ - (void)beginRefreshing; /** * === 子类可以重写该方法实现新的刷新效果 === * * 结束刷新 */ - (void)endRefresh; @end
// // RefreshObject.m // UIScrollView // // Created by YouXianMing on 15/6/24. // Copyright (c) 2015年 YouXianMing. All rights reserved. // #import "RefreshObject.h" @interface RefreshObject () @end @implementation RefreshObject - (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context { // 当前位置 float currentPostion = _scrollView.contentOffset.y; if (_scrollView.isDragging) { // 拖拽中 if (_state == NORMAL_STATE) { // 获取位移的信息 if (_delegate) { CGFloat percent = 0; if (currentPostion <= 0) { percent = -currentPostion / _height; } [_delegate moving:self offset:currentPostion percent:percent]; } } } else { // 停止拖拽 if (currentPostion < -_height) { [self beginRefreshing]; } } } - (void)beginRefreshing { if (_state == NORMAL_STATE) { _state = REFRESH_STATE; if (_delegate) { [_delegate startRefreshing:self]; } [UIView animateWithDuration:0.3 animations:^{ _scrollView.contentInset = UIEdgeInsetsMake(_height, 0, 0, 0); } completion:^(BOOL finished) { }]; } } - (void)endRefresh { if (_delegate) { [_delegate endRefresh:self]; } [UIView animateWithDuration:0.3f animations:^{ _scrollView.contentInset = UIEdgeInsetsMake(0, 0, 0, 0); } completion:^(BOOL finished) { _state = NORMAL_STATE; }]; } @end
// // UIScrollView+RefreshObject.h // UIScrollView // // Created by YouXianMing on 15/6/24. // Copyright (c) 2015年 YouXianMing. All rights reserved. // #import <UIKit/UIKit.h> #import "RefreshObject.h" @interface UIScrollView (RefreshObject) /** * 需要主动赋值 */ @property (nonatomic, strong) RefreshObject *refreshObject; /** * 添加观察者 */ - (void)addObserver; /** * 移除观察者 */ - (void)removeObserver; @end
// // UIScrollView+RefreshObject.m // UIScrollView // // Created by YouXianMing on 15/6/24. // Copyright (c) 2015年 YouXianMing. All rights reserved. // #import "UIScrollView+RefreshObject.h" #import <objc/runtime.h> @implementation UIScrollView (RefreshObject) #pragma mark - 添加属性 @dynamic refreshObject; NSString * const _recognizerRefreshObject = @"recognizerRefreshObject"; - (void)setRefreshObject:(RefreshObject *)refreshObject { objc_setAssociatedObject(self, (__bridge const void *)(_recognizerRefreshObject), refreshObject, OBJC_ASSOCIATION_RETAIN_NONATOMIC); } - (RefreshObject *)refreshObject { return objc_getAssociatedObject(self, (__bridge const void *)(_recognizerRefreshObject)); } #pragma mark - - (void)addObserver { if (self.refreshObject && self.refreshObject.scrollView == nil) { // 获取scrollView self.refreshObject.scrollView = self; // 添加监听 [self addObserver:self.refreshObject forKeyPath:@"contentOffset" options:NSKeyValueObservingOptionNew | NSKeyValueObservingOptionOld context:nil]; } } - (void)removeObserver { if (self.refreshObject) { // 移除监听 [self removeObserver:self.refreshObject forKeyPath:@"contentOffset"]; self.refreshObject.scrollView = nil; self.refreshObject = nil; } } @end
细节
继承协议 RefreshObjectAnimationProtocal 并实现协议方法即可,使用的话,如下所示