New file |
| | |
| | | // 代码地址: 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:方法调用完毕、设置完文字后再去布局子控件 |
| | | dispatch_async(dispatch_get_main_queue(), ^{ |
| | | [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 |
| | | { |
| | | dispatch_async(dispatch_get_main_queue(), ^{ |
| | | 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 |
| | | { |
| | | dispatch_async(dispatch_get_main_queue(), ^{ |
| | | 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 |