zoukankan      html  css  js  c++  java
  • iOS学习系列 UITableView下拉更新/上提加载的实现

    可以利用:http://www.cocoacontrols.com/platforms/ios/controls/ah3dpullrefresh 的Demo。

    可以采用Category的方式,对于UITableView进行扩展(类似于动态创建PushView),例如UITableView+PushAndLoadRefresh.h;而UITableView只要调用扩展方法,通过block回调,重新刷新列表而达到目的。这样还使得UI上最大的松耦合。

      

     源代码如下:

    UIScrollView+AH3DPullRefresh.h

    #import <UIKit/UIKit.h>

    @class AHPullToRefreshView;

    @interface UIScrollView (AH3DPullRefresh)

    @property (nonatomic, retain) AHPullToRefreshView * pullToRefreshView;
    @property (nonatomic, retain) AHPullToRefreshView * pullToLoadMoreView;

    #pragma mark - Init

    /**
     Sets the pull to refresh handler. Call this method to initialize the pull to refresh view.
     @param handler The block to be executed when the pull to refresh view is pulled and released.
     
    */
    - (void)setPullToRefreshHandler:(void (^)(void))handler;

    /**
     Sets the pull to load more handler. Call this method to initialize the pull to load more view.
     @param handler The block to be executed when the pull to load more view is pulled and released.
     
    */
    - (void)setPullToLoadMoreHandler:(void (^)(void))handler;

    #pragma mark - Action

    /**
     Pulls the scrollview to the top in order to refresh the contents.
     The intented use of this method is to pull refresh programatically.
     
    */
    - (void)pullToRefresh;

    /**
     Pulls the scrollview to the bottom in order to load more contents.
     The intented use of this methos is to pull to load more programmatically.
     
    */
    - (void)pullToLoadMore;

    /**
     Hides the pull refresh view. Use it to notify the pull refresh view that the content have been refreshed. 
     
    */
    - (void)refreshFinished;

    /**
     Hides the pull to load more view. Use it to notify the pull to load more view that the content have been refreshed. 
     
    */
    - (void)loadMoreFinished;

    #pragma mark - Customization

    /**
     Returns the pull to refresh label.
     @return the pull to refresh label.
     
    */
    - (UILabel *)pullToRefreshLabel;

    /**
     Sets the pull to refresh view's background color. Default: white.
     @param backgroundColor The background color.
     
    */
    - (void)setPullToRefreshViewBackgroundColor:(UIColor *)backgroundColor;

    /**
     Sets the activity indicator style of the pull to refresh view.
     @param style The activity indicator style.
     
    */
    - (void)setPullToRefreshViewActivityIndicatorStyle:(UIActivityIndicatorViewStyle)style;

    /**
     Sets the text when pulling the pull to refresh view.
     Default: NSLocalizedString(@"Continue pulling to refresh",@"")
     @param pullingText The text to display when pulling the view.
     
    */
    - (void)setPullToRefreshViewPullingText:(NSString *)pullingText;

    /**
     Sets the text when the pull to refresh view is pulled to the maximum to suggest the user release to refresh.
     Default: NSLocalizedString(@"Release to refresh",@"")
     @param releaseText The text to display to suggest the user release the scrollview.
     
    */
    - (void)setPullToRefreshViewReleaseText:(NSString *)releaseText;

    /**
     Sets the text when the pull to refresh view has been released to tell the user that the content is being loaded.
     Default: NSLocalizedString(@"Loading...",@"")
     @param loadingText The text to display while refreshing.
     
    */
    - (void)setPullToRefreshViewLoadingText:(NSString *)loadingText;

    /**
     Sets the text when the pull to refresh view has finished loading.
     Default: NSLocalizedString(@"Loaded!",@"")
     @param loadedText The text to display when the contents has been refreshed.
     
    */
    - (void)setPullToRefreshViewLoadedText:(NSString *)loadedText;

    /**
     Returns the pull to load more label.
     @return the pull to load more label.
     
    */
    - (UILabel *)pullToLoadMoreLabel;

    /**
     Sets the pull to load more view's background color. Default: white.
     @param backgroundColor The background color.
     
    */
    - (void)setPullToLoadMoreViewBackgroundColor:(UIColor *)backgroundColor;

    /**
     Sets the activity indicator style of the pull to load more view.
     @param style The activity indicator style.
     
    */
    - (void)setPullToLoadMoreViewActivityIndicatorStyle:(UIActivityIndicatorViewStyle)style;

    /**
     Sets the text when pulling the pull to load more view.
     Default: NSLocalizedString(@"Continue pulling to refresh",@"")
     @param pullingText The text to display when pulling the view.
     
    */
    - (void)setPullToLoadMoreViewPullingText:(NSString *)pullingText;

    /**
     Sets the text when the pull to load more view is pulled to the maximum to suggest the user release to refresh.
     Default: NSLocalizedString(@"Release to refresh",@"")
     @param releaseText The text to display to suggest the user release the scrollview.
     
    */
    - (void)setPullToLoadMoreViewReleaseText:(NSString *)releaseText;

    /**
     Sets the text when the pull to load more view has been released to tell the user that the content is being loaded.
     Default: NSLocalizedString(@"Loading...",@"")
     @param loadingText The text to display while refreshing.
     
    */
    - (void)setPullToLoadMoreViewLoadingText:(NSString *)loadingText;

    /**
     Sets the text when the pull to load more view has finished loading.
     Default: NSLocalizedString(@"Loaded!",@"")
     @param loadedText The text to display when the contents has been refreshed.
     
    */
    - (void)setPullToLoadMoreViewLoadedText:(NSString *)loadedText;

    @end

    UIScrollView+AH3DPullRefresh.m 

    #import "UIScrollView+AH3DPullRefresh.h"

    #import <objc/runtime.h>
    #import <QuartzCore/QuartzCore.h>

    // --------------------------------------------------------------------------------
    #pragma mark - Helpers

    #define AHRelease(object) [object release]; object = nil
    #define CATransform3DPerspective(t, x, y) (CATransform3DConcat(t, CATransform3DMake(1, 0, 0, x, 0, 1, 0, y, 0, 0, 1, 0, 0, 0, 0, 1)))
    #define CATransform3DMakePerspective(x, y) (CATransform3DPerspective(CATransform3DIdentity, x, y))

    CG_INLINE CATransform3D CATransform3DMake(CGFloat m11, CGFloat m12, CGFloat m13, CGFloat m14,
                                              CGFloat m21, CGFloat m22, CGFloat m23, CGFloat m24,
                                              CGFloat m31, CGFloat m32, CGFloat m33, CGFloat m34,
                                              CGFloat m41, CGFloat m42, CGFloat m43, CGFloat m44) {
        CATransform3D t;
        t.m11 = m11; t.m12 = m12; t.m13 = m13; t.m14 = m14;
        t.m21 = m21; t.m22 = m22; t.m23 = m23; t.m24 = m24;
        t.m31 = m31; t.m32 = m32; t.m33 = m33; t.m34 = m34;
        t.m41 = m41; t.m42 = m42; t.m43 = m43; t.m44 = m44;
        return t;
    }

    // --------------------------------------------------------------------------------
    #pragma mark - [Interface] AHPullToRefreshView

    /**
     Defines the possible states of the pull to refresh view.
     
    */
    typedef enum {
        AHPullViewStateHidden = 1,                // Not visible
        AHPullViewStateVisible,                   // Visible but won't trigger the loading if the user releases
        AHPullViewStateTriggered,                 // If the user releases the scrollview it will load
        AHPullViewStateTriggeredProgramatically,  // When triggering it programmatically
        AHPullViewStateLoading,                   // Loading
        AHPullViewStateLoadingProgramatically     // Loading when triggered programatically
    } AHPullViewState;

    static CGFloat const kAHPullView_ViewHeight = 60.0;

    #define kAHPullView_ContentOffsetKey    @"contentOffset"
    #define kAHPullView_FrameKey            @"frame"

    @interface AHPullToRefreshView : UIView {
        
        AHPullViewState _state;                         // Current state

        UIScrollView * _scrollView;                     // The linked scrollview
        BOOL _isObservingScrollView;                    // If it's observing (KVO) the scrollview
        UIEdgeInsets _originalScrollViewContentInset;   // The original content inset of the scrollview
        
        UIColor * _backgroundColor;                     // The view's background color
        
        UIView * _backgroundView;                       // The background view
        UIView * _shadowView;                           // The view that applies the shadow (black with changing alpha)
        UILabel * _label;                               // Where to display the texts depending on the state
        UIActivityIndicatorView * _activityIndicator;   // Shown while loading
        
        NSString * _pullingText;                        // Customization
        NSString * _releaseText;
        NSString * _loadingText;
        NSString * _loadedText;
    }

    @property (nonatomic, assign) BOOL isObservingScrollView;   // If it's observing (KVO) the scrollview

    @property (nonatomic, retain) UILabel * label;

    @property (nonatomic, retain) NSString * pullingText;       // Displayed in _label while pulling
    @property (nonatomic, retain) NSString * releaseText;       // Displayed in _label before releasing
    @property (nonatomic, retain) NSString * loadingText;       // Displayed in _label while loading
    @property (nonatomic, retain) NSString * loadedText;        // Displayed in _label when loading did finish

    @property (nonatomic, copy) void (^pullToRefreshHandler)(void);   // The block executed when triggering pull refresh
    @property (nonatomic, copy) void (^pullToLoadMoreHandler)(void);  // The block executed when triggering pull load more

    /**
     Initializes the view with the linked scrollview.
     @param scrollView The scrollview where to apply the pull refresh view.
     
    */
    - (id)initWithScrollView:(UIScrollView *)scrollView;

    /**
     Pulls the scrollview to refresh the contents, scrolling it up.
     The intented use of this method is to pull refresh programatically.
     
    */
    - (void)pullToRefresh;

    /**
     Hides the pull refresh view. Use it to notify the pull refresh view that the content have been refreshed. 
     
    */
    - (void)refreshFinished;

    /**
     Sets the background color.
     @param backgroundColor the background color.
     
    */
    - (void)setBackgroundColor:(UIColor *)backgroundColor;

    /**
     Sets the activity indicator style, displayed while loading.
     @param style the activity indicator style.
     
    */
    - (void)setActivityIndicatorStyle:(UIActivityIndicatorViewStyle)style;

    @end

    // --------------------------------------------------------------------------------
    #pragma mark - [Interface] AHPullToRefreshView (Private)

    @interface AHPullToRefreshView (Private)

    - (void)startObservingScrollView;
    - (void)stopObservingScrollView;

    - (void)scrollViewDidScroll:(CGPoint)contentOffset;
    - (void)setScrollViewContentInset:(UIEdgeInsets)contentInset;
    - (UIEdgeInsets)scrollViewContentInset;
    - (void)setState:(AHPullViewState)state;
    - (void)layoutSubviews:(NSTimer *)timer;

    - (void)pullAfterProgrammaticScroll;
    - (void)layoutSubviewsToMaxFraction;

    @end

    // --------------------------------------------------------------------------------
    #pragma mark - [Interface] AHTableView (Private)

    @interface UIScrollView (AHTableViewPrivate)

    @property (nonatomic, assign) BOOL isPullToRefreshEnabled;
    @property (nonatomic, assign) BOOL isPullToLoadMoreEnabled;

    @end 

    // --------------------------------------------------------------------------------
    #pragma mark - AHPullToRefreshView

    @implementation AHPullToRefreshView

    @synthesize isObservingScrollView = _isObservingScrollView;

    @synthesize label = _label;

    @synthesize pullingText = _pullingText;
    @synthesize releaseText = _releaseText;
    @synthesize loadingText = _loadingText;
    @synthesize loadedText = _loadedText;

    @synthesize pullToRefreshHandler;
    @synthesize pullToLoadMoreHandler;

    #pragma mark - View lifecycle

    - (id)initWithScrollView:(UIScrollView *)scrollView {
        
        self = [super initWithFrame:CGRectMake(0, -kAHPullView_ViewHeight/2, _scrollView.bounds.size.width, kAHPullView_ViewHeight)];

        if (self) {
            
            // View setup
            [self setAutoresizingMask:UIViewAutoresizingFlexibleWidth];
            
            // Ivars init
            _scrollView = scrollView;
            _originalScrollViewContentInset = [_scrollView contentInset];
            [self setBackgroundColor:[UIColor whiteColor]];

            _pullingText = [NSLocalizedString(@"Continue pulling to refresh",@"") retain];
            _releaseText = [NSLocalizedString(@"Release to refresh",@"") retain];
            _loadingText = [NSLocalizedString(@"Loading...",@"") retain];
            _loadedText = [NSLocalizedString(@"Loaded!",@"") retain];
        }
        return self;
    }

    - (void)dealloc {
        
        [self stopObservingScrollView];
        
        AHRelease(_backgroundView);
        AHRelease(_shadowView);
        self.label = nil;
        AHRelease(_activityIndicator);
        AHRelease(_backgroundColor);
        
        self.pullingText = nil;
        self.releaseText = nil;
        self.loadingText = nil;
        self.loadedText = nil;
        
        self.pullToRefreshHandler = nil;
        
        [super dealloc];
    }

    #pragma mark - Public methods

    - (void)pullToRefresh {

        // If the it's actually loading or being pulled we avoid loading
        if (_state != AHPullViewStateHidden) {
            return;
        }
        
        // Stop observing scrollview
        [self stopObservingScrollView];
        
        // If pull to load more is not enabled then scroll to top
        BOOL isPullToLoadMoreEnabled = [_scrollView isPullToLoadMoreEnabled];
        if (!isPullToLoadMoreEnabled) {
            [_scrollView scrollRectToVisible:CGRectMake(00, CGRectGetWidth([_scrollView frame]), CGRectGetHeight([_scrollView frame])) animated:YES];
        }

        // Set the state to triggered programmatically
        [self setState:AHPullViewStateTriggeredProgramatically];
        
        // If it's triggered programatically avoid the user interaction
        [_scrollView setScrollEnabled:NO];
            
        // The delay to prevent overlapping animations. It will be between 0.1 and 0.5 seconds
        CGFloat delay = MAX(MIN(_scrollView.contentOffset.y/CGRectGetHeight([_scrollView frame]),0.1),0.5);
        [self performSelector:@selector(pullAfterProgrammaticScroll) withObject:nil afterDelay:delay];    
    }

    - (void)pullToLoadMore {
        
        // If the it's actually loading or being pulled we avoid loading
        if (_state != AHPullViewStateHidden) {
            return;
        }
        
        // Stop observing scrollview
        [self stopObservingScrollView];
        
        // If pull to refresh is not enabled then scroll to bottom
        BOOL isPullToRefreshEnabled = [_scrollView isPullToRefreshEnabled];
        if (!isPullToRefreshEnabled) {
            CGRect rect = CGRectMake(0, _scrollView.contentSize.height - CGRectGetHeight([_scrollView frame]), CGRectGetWidth([_scrollView frame]), CGRectGetHeight([_scrollView frame]));
            [_scrollView scrollRectToVisible:rect animated:YES];
        }
        
        // Set the state to triggered programmatically
        [self setState:AHPullViewStateTriggeredProgramatically];
        
        // If it's triggered programatically avoid the user interaction
        [_scrollView setScrollEnabled:NO];
        
        // The delay to prevent overlapping animations. It will be between 0.1 and 0.5 seconds
        CGFloat delay = MAX(MIN(_scrollView.contentOffset.y/_scrollView.contentSize.height,0.1),0.5);
        [self performSelector:@selector(pullAfterProgrammaticScroll) withObject:nil afterDelay:delay];
    }

    - (void)refreshFinished {
        
        // Set the state to hidden with a delay
        AHPullViewState state = AHPullViewStateHidden;
        SEL selector = @selector(setState:);
        NSMethodSignature *ms = [self methodSignatureForSelector:selector];
        NSInvocation * invocation = [NSInvocation invocationWithMethodSignature:ms];
        [invocation setTarget:self];
        [invocation setSelector:selector];
        [invocation setArgument:&state atIndex:2];
        
        // Note: if called programatically quickly has a visual bug that the unfolding of the 3d view remains stuck. That's why there's a delay.
        if (_state == AHPullViewStateLoadingProgramatically) {
            [invocation performSelector:@selector(invoke) withObject:nil afterDelay:0.3];
        }
        else {
            [invocation performSelector:@selector(invoke) withObject:nil afterDelay:0.0];
        }
        
        // Apply an alpha anim to the view
        [UIView animateWithDuration:0.3 
                         animations:^{[_scrollView pullToLoadMoreView].alpha = 0;}
                         completion:^(BOOL finished){ if (finished) { [_scrollView pullToLoadMoreView].alpha = 1;}}];
        
        // Show the user the scroll indicators
        [_scrollView performSelector:@selector(flashScrollIndicators) withObject:nil afterDelay:0.35];
    }

    - (void)setPullToRefreshHandler:(void (^)(void))handler {
        
        [pullToRefreshHandler release];
        pullToRefreshHandler = [handler copy];
        
        // UI setup
        [_scrollView addSubview:self];
        [_scrollView sendSubviewToBack:self];
        
        _backgroundView = [[UIView alloc] initWithFrame:CGRectMake(00, CGRectGetWidth(_scrollView.frame), CGRectGetHeight(self.frame))];
        [_backgroundView.layer setAnchorPoint:CGPointMake(0.51.0)];
        [self.layer addSublayer:_backgroundView.layer];
        
        _shadowView = [[UIView alloc] initWithFrame:CGRectMake(00, CGRectGetWidth(_scrollView.frame), CGRectGetHeight(self.frame))];
        [_shadowView.layer setAnchorPoint:CGPointMake(0.51.0)];
        [self.layer addSublayer:_shadowView.layer];
        
        _label = [[UILabel alloc] initWithFrame:[_backgroundView frame]];
        _label.text = _loadedText;
        _label.font = [UIFont boldSystemFontOfSize:14];
        [_label setTextAlignment:UITextAlignmentCenter];
        _label.backgroundColor = [UIColor clearColor];
        _label.textColor = [UIColor darkGrayColor];
        [_label setCenter:_backgroundView.center];    
        [self addSubview:_label];
        
        _activityIndicator = [[UIActivityIndicatorView alloc] initWithActivityIndicatorStyle:UIActivityIndicatorViewStyleGray];
        _activityIndicator.hidesWhenStopped = YES;
        [self addSubview:_activityIndicator];
        
        // Set the state to hidden
        [self setState:AHPullViewStateHidden];
    }

    - (void)setPullToLoadMoreHandler:(void (^)(void))handler {
        
        [pullToLoadMoreHandler release];
        pullToLoadMoreHandler = [handler copy];
        
        // UI setup
        [_scrollView addSubview:self];
        
        _backgroundView = [[UIView alloc] initWithFrame:CGRectMake(00, CGRectGetWidth(_scrollView.frame), CGRectGetHeight(self.frame))];
        [_backgroundView.layer setAnchorPoint:CGPointMake(0.51.0)];
        [self.layer addSublayer:_backgroundView.layer];
        
        _shadowView = [[UIView alloc] initWithFrame:CGRectMake(00, CGRectGetWidth(_scrollView.frame), CGRectGetHeight(self.frame))];
        [_shadowView.layer setAnchorPoint:CGPointMake(0.51.0)];
        [self.layer addSublayer:_shadowView.layer];
        
        _label = [[UILabel alloc] initWithFrame:[_backgroundView frame]];
        _label.text = _loadedText;
        _label.font = [UIFont boldSystemFontOfSize:14];
        [_label setTextAlignment:UITextAlignmentCenter];
        _label.backgroundColor = [UIColor clearColor];
        _label.textColor = [UIColor darkGrayColor];
        [_label setCenter:_backgroundView.center];    
        [self addSubview:_label];
        
        _activityIndicator = [[UIActivityIndicatorView alloc] initWithActivityIndicatorStyle:UIActivityIndicatorViewStyleGray];
        _activityIndicator.hidesWhenStopped = YES;
        [self addSubview:_activityIndicator];
        
        // Set the state to hidden
        [self setState:AHPullViewStateHidden];
    }

    // This method is actually an UIView override
    - (void)setBackgroundColor:(UIColor *)backgroundColor {
        
        // Set the color for the background view instead of the actual view
        [_backgroundColor release];
        _backgroundColor = [backgroundColor retain];
        [_backgroundView setBackgroundColor:_backgroundColor];
    }

    - (void)setActivityIndicatorStyle:(UIActivityIndicatorViewStyle)style {

        [_activityIndicator setActivityIndicatorViewStyle:style];

     调用代码:

        // Set the pull to refresh handler block
        [_tableView setPullToRefreshHandler:^{
            
            /**
             Note: Here you should deal perform a webservice request, CoreData query or 
             whatever instead of this dummy code ;-)
             
    */
            NSArray * newRows = [NSArray arrayWithObjects:
                                 [kDataArray objectAtIndex:rand()%33],
                                 [kDataArray objectAtIndex:rand()%33], nil];
            [self performSelector:@selector(dataDidRefresh:) withObject:newRows afterDelay:5.0];
        }];
        
        // Set the pull to laod more handler block
        [_tableView setPullToLoadMoreHandler:^{
            
            /**
             Note: Here you should deal perform a webservice request, CoreData query or 
             whatever instead of this dummy code ;-)
             
    */
            NSArray * newRows = [NSArray arrayWithObjects:
                                 [kDataArray objectAtIndex:rand()%33],
                                 [kDataArray objectAtIndex:rand()%33], nil];
            [self performSelector:@selector(dataDidLoadMore:) withObject:newRows afterDelay:5.0];

        }]; 


  • 相关阅读:
    React中路由的基本使用
    React中props
    一款超级炫酷的编辑代码的插件 Power Mode
    React中使用styled-components的基础使用
    对ES6的一次小梳理
    动态规划法(七)鸡蛋掉落问题(二)
    动态规划法(六)鸡蛋掉落问题(一)(egg dropping problem)
    三对角线性方程组(tridiagonal systems of equations)的求解
    Sherman-Morrison公式及其应用
    动态规划法(四)0-1背包问题(0-1 Knapsack Problem)
  • 原文地址:https://www.cnblogs.com/liping13599168/p/2727624.html
Copyright © 2011-2022 走看看