惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

Blog — PlanetScale
Blog — PlanetScale
Webroot Blog
Webroot Blog
T
Troy Hunt's Blog
S
Secure Thoughts
S
Security @ Cisco Blogs
S
Security Affairs
Forbes - Security
Forbes - Security
W
WeLiveSecurity
H
Hacker News: Front Page
T
Threatpost
Google Online Security Blog
Google Online Security Blog
S
Schneier on Security
有赞技术团队
有赞技术团队
WordPress大学
WordPress大学
www.infosecurity-magazine.com
www.infosecurity-magazine.com
博客园 - Franky
腾讯CDC
IT之家
IT之家
博客园 - 聂微东
L
LINUX DO - 最新话题
罗磊的独立博客
Hacker News - Newest:
Hacker News - Newest: "LLM"
freeCodeCamp Programming Tutorials: Python, JavaScript, Git & More
博客园 - 三生石上(FineUI控件)
Hacker News: Ask HN
Hacker News: Ask HN
C
CXSECURITY Database RSS Feed - CXSecurity.com
C
Cybersecurity and Infrastructure Security Agency CISA
C
CERT Recently Published Vulnerability Notes
Know Your Adversary
Know Your Adversary
V
Vulnerabilities – Threatpost
cs.CV updates on arXiv.org
cs.CV updates on arXiv.org
博客园_首页
奇客Solidot–传递最新科技情报
奇客Solidot–传递最新科技情报
Cisco Talos Blog
Cisco Talos Blog
S
SegmentFault 最新的问题
酷 壳 – CoolShell
酷 壳 – CoolShell
Hugging Face - Blog
Hugging Face - Blog
L
LINUX DO - 热门话题
美团技术团队
G
GRAHAM CLULEY
T
The Exploit Database - CXSecurity.com
AI
AI
Application and Cybersecurity Blog
Application and Cybersecurity Blog
Jina AI
Jina AI
Help Net Security
Help Net Security
N
News | PayPal Newsroom
月光博客
月光博客
Spread Privacy
Spread Privacy
K
KPMG report finds enterprise disconnect between AI and its ROI | CIO
N
News and Events Feed by Topic

博客园 - Leepy

AI应用平台搭建之旅(上) - 框架篇(附:AICon大会阿里国际Agent应用平台分享) 阿里巴巴LangEngine开源了!支撑亿级网关规模的高可用Java原生AI应用开发框架 在mac上安装Go语言初体验 iOS学习系列 - 标签Tag列表的实现 iOS学习系列 - MonoTouch绑定原生Obj-C静态库的实现 iOS学习系列 - 在iOS客户端实现google oauth2登录以及在asp.net服务端上form认证 iOS学习系列 - 利用ASIHTTPRequest实现异步队列 iOS学习系列 - 扩展机制category与associative Wind.js在移动跨平台框架PhoneGap中的异步体验 Mono for Andriod学习与实践(1)— 初体验 阿里技术嘉年华官网上线啦! Silverlight实现对Sql Server Profiler的SQL实时监控 利用Mono.Cecil动态修改程序集来破解商业组件(仅用于研究学习) Silverlight 4以下版本模拟鼠标双击事件 利用Nginx+Mono+Fastcgi代替IIS对Asp.Net进行反向代理 Thrift初探:简单实现C#通讯服务程序 对于.Net中C#指针的研究 各大主流.Net的IOC框架性能测试比较 依赖注入框架Autofac的简单使用
iOS学习系列 - UITableView下拉更新/上提加载的实现
Leepy · 2012-10-17 · via 博客园 - Leepy

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

#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

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