UIScrollView增長刷新

一、app

if (!self.scrollView) {動畫

            CGRect frame = CGRectMake(0.0, 0.0, CGRectGetWidth(self.view.frame), CGRectGetHeight(self.view.frame));網站

            UIScrollView *scrollView = [[UIScrollView alloc] initWithFrame:frame];atom

            //增長這個滾動事件是爲了執行BaseViewController中的scrollViewDidEndDragging事件,滾動立馬隱藏鍵盤spa

            scrollView.delegate = self;.net

            scrollView.backgroundColor = [UIColor clearColor];code

            [scrollView addHeaderWithTarget:self action:@selector(loadData)];component

 

            [self.view addSubview:scrollView];orm

            self.scrollView = scrollView;事件

 

            //爲了讓scrollView能夠滾動,設置contentSize

            self.scrollView.contentSize = CGSizeMake(CGRectGetWidth(self.view.frame), CGRectGetHeight(self.view.frame) + 10);

        } else {

            [self.scrollView headerEndRefreshing];

        }

 

------------------------------------------------------------------------------------------------------------

//

//  UIScrollView+MJRefresh.h

//  MJRefreshExample

//

//  Created by MJ Lee on 14-5-28.

//  Copyright (c) 2014年 itcast. All rights reserved.

//

 

// 版權屬於原做者

// http://code4app.com (cn) http://code4app.net (en)

// 發佈代碼於最專業的源碼分享網站: Code4App.com

 

#import <UIKit/UIKit.h>

 

@interface UIScrollView (MJRefresh)

#pragma mark - 下拉刷新

/**

 *  添加一個下拉刷新頭部控件

 *

 *  @param callback 回調

 */

- (void)addHeaderWithCallback:(void (^)())callback;

 

/**

 *  添加一個下拉刷新頭部控件

 *

 *  @param target 目標

 *  @param action 回調方法

 */

- (void)addHeaderWithTarget:(id)target action:(SEL)action;

 

/**

 *  移除下拉刷新頭部控件

 */

- (void)removeHeader;

 

/**

 *  主動讓下拉刷新頭部控件進入刷新狀態

 */

- (void)headerBeginRefreshing;

 

/**

 *  讓下拉刷新頭部控件中止刷新狀態

 */

- (void)headerEndRefreshing;

 

/**

 *  下拉刷新頭部控件的可見性

 */

@property (nonatomic, assign, getter = isHeaderHidden) BOOL headerHidden;

 

/**

 *  是否正在下拉刷新

 */

@property (nonatomic, assign, readonly, getter = isHeaderRefreshing) BOOL headerRefreshing;

 

#pragma mark - 上拉刷新

/**

 *  添加一個上拉刷新尾部控件

 *

 *  @param callback 回調

 */

- (void)addFooterWithCallback:(void (^)())callback;

 

/**

 *  添加一個上拉刷新尾部控件

 *

 *  @param target 目標

 *  @param action 回調方法

 */

- (void)addFooterWithTarget:(id)target action:(SEL)action;

 

/**

 *  移除上拉刷新尾部控件

 */

- (void)removeFooter;

 

/**

 *  主動讓上拉刷新尾部控件進入刷新狀態

 */

- (void)footerBeginRefreshing;

 

/**

 *  讓上拉刷新尾部控件中止刷新狀態

 */

- (void)footerEndRefreshing;

 

/**

 *  上拉刷新頭部控件的可見性

 */

@property (nonatomic, assign, getter = isFooterHidden) BOOL footerHidden;

 

/**

 *  是否正在上拉刷新

 */

@property (nonatomic, assign, readonly, getter = isFooterRefreshing) BOOL footerRefreshing;

 

/**

 *  設置尾部控件的文字

 */

@property (copy, nonatomic) NSString *footerPullToRefreshText; // 默認:@"上拉能夠加載更多數據"

@property (copy, nonatomic) NSString *footerReleaseToRefreshText; // 默認:@"鬆開當即加載更多數據"

@property (copy, nonatomic) NSString *footerRefreshingText; // 默認:@"MJ哥正在幫你加載數據..."

 

/**

 *  設置頭部控件的文字

 */

@property (copy, nonatomic) NSString *headerPullToRefreshText; // 默認:@"下拉能夠刷新"

@property (copy, nonatomic) NSString *headerReleaseToRefreshText; // 默認:@"鬆開當即刷新"

@property (copy, nonatomic) NSString *headerRefreshingText; // 默認:@"MJ哥正在幫你刷新..."

@end

 --------------------------------------------------------------------

//

//  UIScrollView+MJRefresh.m

//  MJRefreshExample

//

//  Created by MJ Lee on 14-5-28.

//  Copyright (c) 2014年 itcast. All rights reserved.

//

 

// 版權屬於原做者

// http://code4app.com (cn) http://code4app.net (en)

// 發佈代碼於最專業的源碼分享網站: Code4App.com

 

#import "UIScrollView+MJRefresh.h"

#import "MJRefreshHeaderView.h"

#import "MJRefreshFooterView.h"

#import <objc/runtime.h>

 

@interface UIScrollView()

@property (weak, nonatomic) MJRefreshHeaderView *header;

@property (weak, nonatomic) MJRefreshFooterView *footer;

@end

 

 

@implementation UIScrollView (MJRefresh)

 

#pragma mark - 運行時相關

static char MJRefreshHeaderViewKey;

static char MJRefreshFooterViewKey;

 

- (void)setHeader:(MJRefreshHeaderView *)header {

    [self willChangeValueForKey:@"MJRefreshHeaderViewKey"];

    objc_setAssociatedObject(self, &MJRefreshHeaderViewKey,

                             header,

                             OBJC_ASSOCIATION_ASSIGN);

    [self didChangeValueForKey:@"MJRefreshHeaderViewKey"];

}

 

- (MJRefreshHeaderView *)header {

    return objc_getAssociatedObject(self, &MJRefreshHeaderViewKey);

}

 

- (void)setFooter:(MJRefreshFooterView *)footer {

    [self willChangeValueForKey:@"MJRefreshFooterViewKey"];

    objc_setAssociatedObject(self, &MJRefreshFooterViewKey,

                             footer,

                             OBJC_ASSOCIATION_ASSIGN);

    [self didChangeValueForKey:@"MJRefreshFooterViewKey"];

}

 

- (MJRefreshFooterView *)footer {

    return objc_getAssociatedObject(self, &MJRefreshFooterViewKey);

}

 

#pragma mark - 下拉刷新

/**

 *  添加一個下拉刷新頭部控件

 *

 *  @param callback 回調

 */

- (void)addHeaderWithCallback:(void (^)())callback

{

    // 1.建立新的header

    if (!self.header) {

        MJRefreshHeaderView *header = [MJRefreshHeaderView header];

        [self addSubview:header];

        self.header = header;

    }

    

    // 2.設置block回調

    self.header.beginRefreshingCallback = callback;

}

 

/**

 *  添加一個下拉刷新頭部控件

 *

 *  @param target 目標

 *  @param action 回調方法

 */

 

- (void)addHeaderWithTarget:(id)target action:(SEL)action

{

    // 1.建立新的header

    if (!self.header) {

        MJRefreshHeaderView *header = [MJRefreshHeaderView header];

        [self addSubview:header];

        self.header = header;

    }

    // 2.設置目標和回調方法

    self.header.beginRefreshingTaget = target;

    self.header.beginRefreshingAction = action;

}

 

/**

 *  移除下拉刷新頭部控件

 */

- (void)removeHeader

{

    [self.header removeFromSuperview];

    self.header = nil;

}

 

/**

 *  主動讓下拉刷新頭部控件進入刷新狀態

 */

- (void)headerBeginRefreshing

{

    [self.header beginRefreshing];

}

 

/**

 *  讓下拉刷新頭部控件中止刷新狀態

 */

- (void)headerEndRefreshing

{

    [self.header endRefreshing];

}

 

/**

 *  下拉刷新頭部控件的可見性

 */

- (void)setHeaderHidden:(BOOL)hidden

{

    self.header.hidden = hidden;

}

 

- (BOOL)isHeaderHidden

{

    return self.header.isHidden;

}

 

- (BOOL)isHeaderRefreshing

{

    return self.header.state == MJRefreshStateRefreshing;

}

 

#pragma mark - 上拉刷新

/**

 *  添加一個上拉刷新尾部控件

 *

 *  @param callback 回調

 */

- (void)addFooterWithCallback:(void (^)())callback

{

    // 1.建立新的footer

    if (!self.footer) {

        MJRefreshFooterView *footer = [MJRefreshFooterView footer];

        [self addSubview:footer];

        self.footer = footer;

    }

    

    // 2.設置block回調

    self.footer.beginRefreshingCallback = callback;

}

 

/**

 *  添加一個上拉刷新尾部控件

 *

 *  @param target 目標

 *  @param action 回調方法

 */

- (void)addFooterWithTarget:(id)target action:(SEL)action

{

    // 1.建立新的footer

    if (!self.footer) {

        MJRefreshFooterView *footer = [MJRefreshFooterView footer];

        [self addSubview:footer];

        self.footer = footer;

    }

    

    // 2.設置目標和回調方法

    self.footer.beginRefreshingTaget = target;

    self.footer.beginRefreshingAction = action;

}

 

/**

 *  移除上拉刷新尾部控件

 */

- (void)removeFooter

{

    [self.footer removeFromSuperview];

    self.footer = nil;

}

 

/**

 *  主動讓上拉刷新尾部控件進入刷新狀態

 */

- (void)footerBeginRefreshing

{

    [self.footer beginRefreshing];

}

 

/**

 *  讓上拉刷新尾部控件中止刷新狀態

 */

- (void)footerEndRefreshing

{

    [self.footer endRefreshing];

}

 

/**

 *  下拉刷新頭部控件的可見性

 */

- (void)setFooterHidden:(BOOL)hidden

{

    self.footer.hidden = hidden;

}

 

- (BOOL)isFooterHidden

{

    return self.footer.isHidden;

}

 

- (BOOL)isFooterRefreshing

{

    return self.footer.state == MJRefreshStateRefreshing;

}

 

/**

 *  文字

 */

- (void)setFooterPullToRefreshText:(NSString *)footerPullToRefreshText

{

    self.footer.pullToRefreshText = footerPullToRefreshText;

}

 

- (NSString *)footerPullToRefreshText

{

    return self.footer.pullToRefreshText;

}

 

- (void)setFooterReleaseToRefreshText:(NSString *)footerReleaseToRefreshText

{

    self.footer.releaseToRefreshText = footerReleaseToRefreshText;

}

 

- (NSString *)footerReleaseToRefreshText

{

    return self.footer.releaseToRefreshText;

}

 

- (void)setFooterRefreshingText:(NSString *)footerRefreshingText

{

    self.footer.refreshingText = footerRefreshingText;

}

 

- (NSString *)footerRefreshingText

{

    return self.footer.refreshingText;

}

 

- (void)setHeaderPullToRefreshText:(NSString *)headerPullToRefreshText

{

    self.header.pullToRefreshText = headerPullToRefreshText;

}

 

- (NSString *)headerPullToRefreshText

{

    return self.header.pullToRefreshText;

}

 

- (void)setHeaderReleaseToRefreshText:(NSString *)headerReleaseToRefreshText

{

    self.header.releaseToRefreshText = headerReleaseToRefreshText;

}

 

- (NSString *)headerReleaseToRefreshText

{

    return self.header.releaseToRefreshText;

}

 

- (void)setHeaderRefreshingText:(NSString *)headerRefreshingText

{

    self.header.refreshingText = headerRefreshingText;

}

 

- (NSString *)headerRefreshingText

{

    return self.header.refreshingText;

}

@end

 ---------------------------------------------------------------------------

//

//  MJRefreshHeaderView.h

//  MJRefresh

//

//  Created by mj on 13-2-26.

//  Copyright (c) 2013年 itcast. All rights reserved.

//  下拉刷新

 

// 版權屬於原做者

// http://code4app.com (cn) http://code4app.net (en)

// 發佈代碼於最專業的源碼分享網站: Code4App.com

 

#import "MJRefreshBaseView.h"

 

@interface MJRefreshHeaderView : MJRefreshBaseView

+ (instancetype)header;

@end

 

--------------------------------------------------------------

//

//  MJRefreshHeaderView.m

//  MJRefresh

//

//  Created by mj on 13-2-26.

//  Copyright (c) 2013年 itcast. All rights reserved.

//  下拉刷新

 

// 版權屬於原做者

// http://code4app.com (cn) http://code4app.net (en)

// 發佈代碼於最專業的源碼分享網站: Code4App.com

 

#import "MJRefreshConst.h"

#import "MJRefreshHeaderView.h"

#import "UIView+MJExtension.h"

#import "UIScrollView+MJExtension.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];

}

 

- (id)initWithFrame:(CGRect)frame

{

    if (self = [super initWithFrame:frame]) {

        self.pullToRefreshText = MJRefreshHeaderPullToRefresh;

        self.releaseToRefreshText = MJRefreshHeaderReleaseToRefresh;

        self.refreshingText = MJRefreshHeaderRefreshing;

    }

    return self;

}

 

- (void)layoutSubviews

{

    [super layoutSubviews];

    

    CGFloat statusX = 0;

    CGFloat statusY = 0;

    CGFloat statusHeight = self.mj_height * 0.5;

    CGFloat statusWidth = self.mj_width;

    // 1.狀態標籤

    self.statusLabel.frame = CGRectMake(statusX, statusY, statusWidth, statusHeight);

    

    // 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];

    // 設置本身的位置和尺寸

    self.mj_y = - self.mj_height;

}

 

#pragma mark - 狀態相關

#pragma mark 設置最後的更新時間

- (void)setLastUpdateTime:(NSDate *)lastUpdateTime

{

    _lastUpdateTime = lastUpdateTime;

    

    // 1.歸檔

    [[NSUserDefaults standardUserDefaults] setObject:lastUpdateTime forKey:MJRefreshHeaderTimeKey];

    [[NSUserDefaults standardUserDefaults] synchronize];

    

    // 2.更新時間

    [self updateTimeLabel];

}

 

#pragma mark 更新時間字符串

- (void)updateTimeLabel

{

    if (!self.lastUpdateTime) return;

    

    // 1.得到年月日

    NSCalendar *calendar = [NSCalendar currentCalendar];

    NSUInteger unitFlags = NSYearCalendarUnit| NSMonthCalendarUnit | NSDayCalendarUnit |NSHourCalendarUnit |NSMinuteCalendarUnit;

    NSDateComponents *cmp1 = [calendar components:unitFlags fromDate:_lastUpdateTime];

    NSDateComponents *cmp2 = [calendar components:unitFlags fromDate:[NSDate date]];

    

    // 2.格式化日期

    NSDateFormatter *formatter = [[NSDateFormatter alloc] init];

    if ([cmp1 day] == [cmp2 day]) { // 今天

        formatter.dateFormat = @"今天 HH:mm";

    } else if ([cmp1 year] == [cmp2 year]) { // 今年

        formatter.dateFormat = @"MM-dd HH:mm";

    } else {

        formatter.dateFormat = @"yyyy-MM-dd HH:mm";

    }

    NSString *time = [formatter stringFromDate:self.lastUpdateTime];

    

    // 3.顯示日期

    self.lastUpdateTimeLabel.text = [NSString stringWithFormat:@"最後更新:%@", time];

}

 

#pragma mark - 監聽UIScrollView的contentOffset屬性

- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context

{

    // 不能跟用戶交互就直接返回

    if (!self.userInteractionEnabled || self.alpha <= 0.01 || self.hidden) return;

 

    // 若是正在刷新,直接返回

    if (self.state == MJRefreshStateRefreshing) return;

 

    if ([MJRefreshContentOffset isEqualToString:keyPath]) {

        [self adjustStateWithContentOffset];

    }

}

 

/**

 *  調整狀態

 */

- (void)adjustStateWithContentOffset

{

    // 當前的contentOffset

    CGFloat currentOffsetY = self.scrollView.mj_contentOffsetY;

    // 頭部控件恰好出現的offsetY

    CGFloat happenOffsetY = - self.scrollViewOriginalInset.top;

    

    // 若是是向上滾動到看不見頭部控件,直接返回

    if (currentOffsetY >= happenOffsetY) return;

    

    if (self.scrollView.isDragging) {

        // 普通 和 即將刷新 的臨界點

        CGFloat normal2pullingOffsetY = happenOffsetY - self.mj_height;

        

        if (self.state == MJRefreshStateNormal && currentOffsetY < normal2pullingOffsetY) {

            // 轉爲即將刷新狀態

            self.state = MJRefreshStatePulling;

        } else if (self.state == MJRefreshStatePulling && currentOffsetY >= normal2pullingOffsetY) {

            // 轉爲普通狀態

            self.state = MJRefreshStateNormal;

        }

    } else if (self.state == MJRefreshStatePulling) {// 即將刷新 && 手鬆開

        // 開始刷新

        self.state = MJRefreshStateRefreshing;

    }

}

 

#pragma mark 設置狀態

- (void)setState:(MJRefreshState)state

{

    // 1.同樣的就直接返回

    if (self.state == state) return;

    

    // 2.保存舊狀態

    MJRefreshState oldState = self.state;

    

    // 3.調用父類方法

    [super setState:state];

    

    // 4.根據狀態執行不一樣的操做

switch (state) {

case MJRefreshStateNormal: // 下拉能夠刷新

        {

            // 刷新完畢

            if (MJRefreshStateRefreshing == oldState) {

                self.arrowImage.transform = CGAffineTransformIdentity;

                // 保存刷新時間

                self.lastUpdateTime = [NSDate date];

                

                [UIView animateWithDuration:MJRefreshSlowAnimationDuration animations:^{

                    self.scrollView.mj_contentInsetTop -= self.mj_height;

                }];

            } else {

                // 執行動畫

                [UIView animateWithDuration:MJRefreshFastAnimationDuration animations:^{

                    self.arrowImage.transform = CGAffineTransformIdentity;

                }];

            }

break;

        }

            

case MJRefreshStatePulling: // 鬆開可當即刷新

        {

            // 執行動畫

            [UIView animateWithDuration:MJRefreshFastAnimationDuration animations:^{

                self.arrowImage.transform = CGAffineTransformMakeRotation(M_PI);

            }];

break;

        }

            

case MJRefreshStateRefreshing: // 正在刷新中

        {

            // 執行動畫

            [UIView animateWithDuration:MJRefreshFastAnimationDuration animations:^{

                // 1.增長滾動區域

                CGFloat top = self.scrollViewOriginalInset.top + self.mj_height;

                self.scrollView.mj_contentInsetTop = top;

                

                // 2.設置滾動位置

                self.scrollView.mj_contentOffsetY = - top;

            }];

break;

        }

            

        default:

            break;

}

}

@end

相關文章
相關標籤/搜索