123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722 |
- //
- // UIScrollView+NTESPullToRefresh.m
- //
- // Created by chris on 15/2/12.
- // Copyright (c) 2015年 Netease. All rights reserved.
- //
- //
- #import <QuartzCore/QuartzCore.h>
- #import "UIScrollView+NTESPullToRefresh.h"
- #define fequal(a,b) (fabs((a) - (b)) < FLT_EPSILON)
- #define fequalzero(a) (fabs(a) < FLT_EPSILON)
- static CGFloat const NTESPullToRefreshViewHeight = 60;
- @interface NTESPullToRefreshArrow : UIView
- @property (nonatomic, strong) UIColor *arrowColor;
- @end
- @interface NTESPullToRefreshView ()
- @property (nonatomic, copy) void (^pullToRefreshActionHandler)(void);
- @property (nonatomic, strong) NTESPullToRefreshArrow *arrow;
- @property (nonatomic, strong) UIActivityIndicatorView *activityIndicatorView;
- @property (nonatomic, strong, readwrite) UILabel *titleLabel;
- @property (nonatomic, strong, readwrite) UILabel *subtitleLabel;
- @property (nonatomic, readwrite) NTESPullToRefreshState state;
- @property (nonatomic, readwrite) NTESPullToRefreshPosition position;
- @property (nonatomic, strong) NSMutableArray *titles;
- @property (nonatomic, strong) NSMutableArray *subtitles;
- @property (nonatomic, strong) NSMutableArray *viewForState;
- @property (nonatomic, weak) UIScrollView *scrollView;
- @property (nonatomic, readwrite) CGFloat originalTopInset;
- @property (nonatomic, readwrite) CGFloat originalBottomInset;
- @property (nonatomic, assign) BOOL wasTriggeredByUser;
- @property (nonatomic, assign) BOOL showsPullToRefresh;
- @property (nonatomic, assign) BOOL showsDateLabel;
- @property(nonatomic, assign) BOOL isObserving;
- - (void)resetScrollViewContentInset;
- - (void)setScrollViewContentInsetForLoading;
- - (void)setScrollViewContentInset:(UIEdgeInsets)insets;
- - (void)rotateArrow:(float)degrees hide:(BOOL)hide;
- @end
- #pragma mark - UIScrollView (NTESPullToRefresh)
- #import <objc/runtime.h>
- static char UIScrollViewPullToRefreshView;
- @implementation UIScrollView (NTESPullToRefresh)
- @dynamic pullToRefreshView, showsPullToRefresh;
- - (void)addPullToRefreshWithActionHandler:(void (^)(void))actionHandler position:(NTESPullToRefreshPosition)position {
-
- if(!self.pullToRefreshView) {
- CGFloat yOrigin;
- switch (position) {
- case NTESPullToRefreshPositionTop:
- yOrigin = -NTESPullToRefreshViewHeight;
- break;
- case NTESPullToRefreshPositionBottom:
- yOrigin = self.contentSize.height;
- break;
- default:
- return;
- }
- NTESPullToRefreshView *view = [[NTESPullToRefreshView alloc] initWithFrame:CGRectMake(0, yOrigin, self.bounds.size.width, NTESPullToRefreshViewHeight)];
- view.pullToRefreshActionHandler = actionHandler;
- view.scrollView = self;
- [self addSubview:view];
-
- view.originalTopInset = self.contentInset.top;
- view.originalBottomInset = self.contentInset.bottom;
- view.position = position;
- self.pullToRefreshView = view;
- self.showsPullToRefresh = YES;
- }
-
- }
- - (void)addPullToRefreshWithActionHandler:(void (^)(void))actionHandler {
- [self addPullToRefreshWithActionHandler:actionHandler position:NTESPullToRefreshPositionTop];
- }
- - (void)triggerPullToRefresh {
- self.pullToRefreshView.state = NTESPullToRefreshStateTriggered;
- [self.pullToRefreshView startAnimating];
- }
- - (void)setPullToRefreshView:(NTESPullToRefreshView *)pullToRefreshView {
- [self willChangeValueForKey:@"SVPullToRefreshView"];
- objc_setAssociatedObject(self, &UIScrollViewPullToRefreshView,
- pullToRefreshView,
- OBJC_ASSOCIATION_ASSIGN);
- [self didChangeValueForKey:@"SVPullToRefreshView"];
- }
- - (NTESPullToRefreshView *)pullToRefreshView {
- return objc_getAssociatedObject(self, &UIScrollViewPullToRefreshView);
- }
- - (void)setShowsPullToRefresh:(BOOL)showsPullToRefresh {
- self.pullToRefreshView.hidden = !showsPullToRefresh;
-
- if(!showsPullToRefresh) {
- if (self.pullToRefreshView.isObserving) {
- [self removeObserver:self.pullToRefreshView forKeyPath:@"contentOffset"];
- [self removeObserver:self.pullToRefreshView forKeyPath:@"contentSize"];
- [self removeObserver:self.pullToRefreshView forKeyPath:@"frame"];
- [self.pullToRefreshView resetScrollViewContentInset];
- self.pullToRefreshView.isObserving = NO;
- }
- }
- else {
- if (!self.pullToRefreshView.isObserving) {
- [self addObserver:self.pullToRefreshView forKeyPath:@"contentOffset" options:NSKeyValueObservingOptionNew context:nil];
- [self addObserver:self.pullToRefreshView forKeyPath:@"contentSize" options:NSKeyValueObservingOptionNew context:nil];
- [self addObserver:self.pullToRefreshView forKeyPath:@"frame" options:NSKeyValueObservingOptionNew context:nil];
- self.pullToRefreshView.isObserving = YES;
-
- CGFloat yOrigin = 0;
- switch (self.pullToRefreshView.position) {
- case NTESPullToRefreshPositionTop:
- yOrigin = -NTESPullToRefreshViewHeight;
- break;
- case NTESPullToRefreshPositionBottom:
- yOrigin = self.contentSize.height;
- break;
- }
-
- self.pullToRefreshView.frame = CGRectMake(0, yOrigin, self.bounds.size.width, NTESPullToRefreshViewHeight);
- }
- }
- }
- - (BOOL)showsPullToRefresh {
- return !self.pullToRefreshView.hidden;
- }
- @end
- #pragma mark - NTESPullToRefresh
- @implementation NTESPullToRefreshView
- // public properties
- @synthesize pullToRefreshActionHandler, arrowColor, textColor, activityIndicatorViewColor, activityIndicatorViewStyle;
- @synthesize state = _state;
- @synthesize scrollView = _scrollView;
- @synthesize showsPullToRefresh = _showsPullToRefresh;
- @synthesize arrow = _arrow;
- @synthesize activityIndicatorView = _activityIndicatorView;
- @synthesize titleLabel = _titleLabel;
- - (id)initWithFrame:(CGRect)frame {
- if(self = [super initWithFrame:frame]) {
-
- // default styling values
- self.activityIndicatorViewStyle = UIActivityIndicatorViewStyleGray;
- self.textColor = [UIColor darkGrayColor];
- self.autoresizingMask = UIViewAutoresizingFlexibleWidth;
- self.state = NTESPullToRefreshStateStopped;
- self.showsDateLabel = NO;
-
- self.titles = [NSMutableArray arrayWithObjects:NSLocalizedString(@"下拉加载...",),
- NSLocalizedString(@"松开刷新...",),
- NSLocalizedString(@"加载中...",),
- nil];
-
- self.subtitles = [NSMutableArray arrayWithObjects:@"", @"", @"", @"", nil];
- self.viewForState = [NSMutableArray arrayWithObjects:@"", @"", @"", @"", nil];
- self.wasTriggeredByUser = YES;
- }
-
- return self;
- }
- - (void)willMoveToSuperview:(UIView *)newSuperview {
- if (self.superview && newSuperview == nil) {
- //use self.superview, not self.scrollView. Why self.scrollView == nil here?
- UIScrollView *scrollView = (UIScrollView *)self.superview;
- if (scrollView.showsPullToRefresh) {
- if (self.isObserving) {
- //If enter this branch, it is the moment just before "SVPullToRefreshView's dealloc", so remove observer here
- [scrollView removeObserver:self forKeyPath:@"contentOffset"];
- [scrollView removeObserver:self forKeyPath:@"contentSize"];
- [scrollView removeObserver:self forKeyPath:@"frame"];
- self.isObserving = NO;
- }
- }
- }
- }
- - (void)layoutSubviews {
-
- for(id otherView in self.viewForState) {
- if([otherView isKindOfClass:[UIView class]])
- [otherView removeFromSuperview];
- }
-
- id customView = [self.viewForState objectAtIndex:self.state];
- BOOL hasCustomView = [customView isKindOfClass:[UIView class]];
-
- self.titleLabel.hidden = hasCustomView;
- self.subtitleLabel.hidden = hasCustomView;
- self.arrow.hidden = hasCustomView;
-
- if(hasCustomView) {
- [self addSubview:customView];
- CGRect viewBounds = [customView bounds];
- CGPoint origin = CGPointMake(roundf((self.bounds.size.width-viewBounds.size.width)/2), roundf((self.bounds.size.height-viewBounds.size.height)/2));
- [customView setFrame:CGRectMake(origin.x, origin.y, viewBounds.size.width, viewBounds.size.height)];
- }
- else {
- switch (self.state) {
- case NTESPullToRefreshStateAll:
- case NTESPullToRefreshStateStopped:
- self.arrow.alpha = 1;
- [self.activityIndicatorView stopAnimating];
- switch (self.position) {
- case NTESPullToRefreshPositionTop:
- [self rotateArrow:0 hide:NO];
- break;
- case NTESPullToRefreshPositionBottom:
- [self rotateArrow:(float)M_PI hide:NO];
- break;
- }
- break;
-
- case NTESPullToRefreshStateTriggered:
- switch (self.position) {
- case NTESPullToRefreshPositionTop:
- [self rotateArrow:(float)M_PI hide:NO];
- break;
- case NTESPullToRefreshPositionBottom:
- [self rotateArrow:0 hide:NO];
- break;
- }
- break;
-
- case NTESPullToRefreshStateLoading:
- [self.activityIndicatorView startAnimating];
- switch (self.position) {
- case NTESPullToRefreshPositionTop:
- [self rotateArrow:0 hide:YES];
- break;
- case NTESPullToRefreshPositionBottom:
- [self rotateArrow:(float)M_PI hide:YES];
- break;
- }
- break;
- }
-
- CGFloat leftViewWidth = MAX(self.arrow.bounds.size.width,self.activityIndicatorView.bounds.size.width);
-
- CGFloat margin = 10;
- CGFloat marginY = 2;
- CGFloat labelMaxWidth = self.bounds.size.width - margin - leftViewWidth;
-
- self.titleLabel.text = [self.titles objectAtIndex:self.state];
-
- NSString *subtitle = [self.subtitles objectAtIndex:self.state];
- self.subtitleLabel.text = subtitle.length > 0 ? subtitle : nil;
-
-
- CGSize titleSize = [self.titleLabel.text boundingRectWithSize:CGSizeMake(labelMaxWidth,self.titleLabel.font.lineHeight)
- options:(NSStringDrawingUsesFontLeading|NSStringDrawingTruncatesLastVisibleLine|NSStringDrawingUsesLineFragmentOrigin)
- attributes:@{NSFontAttributeName: self.titleLabel.font}
- context:NULL].size;
-
- CGSize subtitleSize = [self.subtitleLabel.text boundingRectWithSize:CGSizeMake(labelMaxWidth,self.subtitleLabel.font.lineHeight)
- options:(NSStringDrawingUsesFontLeading|NSStringDrawingTruncatesLastVisibleLine|NSStringDrawingUsesLineFragmentOrigin)
- attributes:@{NSFontAttributeName: self.subtitleLabel.font}
- context:NULL].size;
-
- CGFloat maxLabelWidth = MAX(titleSize.width,subtitleSize.width);
-
- CGFloat totalMaxWidth;
- if (maxLabelWidth) {
- totalMaxWidth = leftViewWidth + margin + maxLabelWidth;
- } else {
- totalMaxWidth = leftViewWidth + maxLabelWidth;
- }
-
- CGFloat labelX = (self.bounds.size.width / 2) - (totalMaxWidth / 2) + leftViewWidth + margin;
-
- if(subtitleSize.height > 0){
- CGFloat totalHeight = titleSize.height + subtitleSize.height + marginY;
- CGFloat minY = (self.bounds.size.height / 2) - (totalHeight / 2);
-
- CGFloat titleY = minY;
- self.titleLabel.frame = CGRectIntegral(CGRectMake(labelX, titleY, titleSize.width, titleSize.height));
- self.subtitleLabel.frame = CGRectIntegral(CGRectMake(labelX, titleY + titleSize.height + marginY, subtitleSize.width, subtitleSize.height));
- }else{
- CGFloat totalHeight = titleSize.height;
- CGFloat minY = (self.bounds.size.height / 2) - (totalHeight / 2);
-
- CGFloat titleY = minY;
- self.titleLabel.frame = CGRectIntegral(CGRectMake(labelX, titleY, titleSize.width, titleSize.height));
- self.subtitleLabel.frame = CGRectIntegral(CGRectMake(labelX, titleY + titleSize.height + marginY, subtitleSize.width, subtitleSize.height));
- }
-
- CGFloat arrowX = (self.bounds.size.width / 2) - (totalMaxWidth / 2) + (leftViewWidth - self.arrow.bounds.size.width) / 2;
- self.arrow.frame = CGRectMake(arrowX,
- (self.bounds.size.height / 2) - (self.arrow.bounds.size.height / 2),
- self.arrow.bounds.size.width,
- self.arrow.bounds.size.height);
- self.activityIndicatorView.center = self.arrow.center;
- }
- }
- #pragma mark - Scroll View
- - (void)resetScrollViewContentInset {
- UIEdgeInsets currentInsets = self.scrollView.contentInset;
- switch (self.position) {
- case NTESPullToRefreshPositionTop:
- currentInsets.top = self.originalTopInset;
- break;
- case NTESPullToRefreshPositionBottom:
- currentInsets.bottom = self.originalBottomInset;
- currentInsets.top = self.originalTopInset;
- break;
- }
- [self setScrollViewContentInset:currentInsets];
- }
- - (void)setScrollViewContentInsetForLoading {
- CGFloat offset = MAX(self.scrollView.contentOffset.y * -1, 0);
- UIEdgeInsets currentInsets = self.scrollView.contentInset;
- switch (self.position) {
- case NTESPullToRefreshPositionTop:
- currentInsets.top = MIN(offset, self.originalTopInset + self.bounds.size.height);
- break;
- case NTESPullToRefreshPositionBottom:
- currentInsets.bottom = MIN(offset, self.originalBottomInset + self.bounds.size.height);
- break;
- }
- [self setScrollViewContentInset:currentInsets];
- }
- - (void)setScrollViewContentInset:(UIEdgeInsets)contentInset {
- [UIView animateWithDuration:0.3
- delay:0
- options:UIViewAnimationOptionAllowUserInteraction|UIViewAnimationOptionBeginFromCurrentState
- animations:^{
- self.scrollView.contentInset = contentInset;
- }
- completion:NULL];
- }
- #pragma mark - Observing
- - (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context {
- if([keyPath isEqualToString:@"contentOffset"])
- [self scrollViewDidScroll:[[change valueForKey:NSKeyValueChangeNewKey] CGPointValue]];
- else if([keyPath isEqualToString:@"contentSize"]) {
- [self layoutSubviews];
-
- CGFloat yOrigin;
- switch (self.position) {
- case NTESPullToRefreshPositionTop:
- yOrigin = -NTESPullToRefreshViewHeight;
- break;
- case NTESPullToRefreshPositionBottom:
- yOrigin = MAX(self.scrollView.contentSize.height, self.scrollView.bounds.size.height);
- break;
- }
- self.frame = CGRectMake(0, yOrigin, self.bounds.size.width, NTESPullToRefreshViewHeight);
- }
- else if([keyPath isEqualToString:@"frame"])
- [self layoutSubviews];
-
- }
- - (void)scrollViewDidScroll:(CGPoint)contentOffset {
- if(self.state != NTESPullToRefreshStateLoading) {
- CGFloat scrollOffsetThreshold = 0;
- switch (self.position) {
- case NTESPullToRefreshPositionTop:
- scrollOffsetThreshold = self.frame.origin.y - self.originalTopInset;
- break;
- case NTESPullToRefreshPositionBottom:
- scrollOffsetThreshold = MAX(self.scrollView.contentSize.height - self.scrollView.bounds.size.height, 0.0f) + self.bounds.size.height + self.originalBottomInset;
- break;
- }
-
- if(!self.scrollView.isDragging && self.state == NTESPullToRefreshStateTriggered)
- self.state = NTESPullToRefreshStateLoading;
- else if(contentOffset.y < scrollOffsetThreshold && self.scrollView.isDragging && self.state == NTESPullToRefreshStateStopped && self.position == NTESPullToRefreshPositionTop)
- self.state = NTESPullToRefreshStateTriggered;
- else if(contentOffset.y >= scrollOffsetThreshold && self.state != NTESPullToRefreshStateStopped && self.position == NTESPullToRefreshPositionTop)
- self.state = NTESPullToRefreshStateStopped;
- else if(contentOffset.y > scrollOffsetThreshold && self.scrollView.isDragging && self.state == NTESPullToRefreshStateStopped && self.position == NTESPullToRefreshPositionBottom)
- self.state = NTESPullToRefreshStateTriggered;
- else if(contentOffset.y <= scrollOffsetThreshold && self.state != NTESPullToRefreshStateStopped && self.position == NTESPullToRefreshPositionBottom)
- self.state = NTESPullToRefreshStateStopped;
- } else {
- CGFloat offset;
- UIEdgeInsets contentInset;
- switch (self.position) {
- case NTESPullToRefreshPositionTop:
- offset = MAX(self.scrollView.contentOffset.y * -1, 0.0f);
- offset = MIN(offset, self.originalTopInset + self.bounds.size.height);
- contentInset = self.scrollView.contentInset;
- self.scrollView.contentInset = UIEdgeInsetsMake(offset, contentInset.left, contentInset.bottom, contentInset.right);
- break;
- case NTESPullToRefreshPositionBottom:
- if (self.scrollView.contentSize.height >= self.scrollView.bounds.size.height) {
- offset = MAX(self.scrollView.contentSize.height - self.scrollView.bounds.size.height + self.bounds.size.height, 0.0f);
- offset = MIN(offset, self.originalBottomInset + self.bounds.size.height);
- contentInset = self.scrollView.contentInset;
- self.scrollView.contentInset = UIEdgeInsetsMake(contentInset.top, contentInset.left, offset, contentInset.right);
- } else if (self.wasTriggeredByUser) {
- offset = MIN(self.bounds.size.height, self.originalBottomInset + self.bounds.size.height);
- contentInset = self.scrollView.contentInset;
- self.scrollView.contentInset = UIEdgeInsetsMake(-offset, contentInset.left, contentInset.bottom, contentInset.right);
- }
- break;
- }
- }
- }
- #pragma mark - Getters
- - (NTESPullToRefreshArrow *)arrow {
- if(!_arrow) {
- _arrow = [[NTESPullToRefreshArrow alloc]initWithFrame:CGRectMake(0, self.bounds.size.height-54, 22, 48)];
- _arrow.backgroundColor = [UIColor clearColor];
- [self addSubview:_arrow];
- }
- return _arrow;
- }
- - (UIActivityIndicatorView *)activityIndicatorView {
- if(!_activityIndicatorView) {
- _activityIndicatorView = [[UIActivityIndicatorView alloc] initWithActivityIndicatorStyle:UIActivityIndicatorViewStyleWhite];
- _activityIndicatorView.hidesWhenStopped = YES;
- [self addSubview:_activityIndicatorView];
- }
- return _activityIndicatorView;
- }
- - (UILabel *)titleLabel {
- if(!_titleLabel) {
- _titleLabel = [[UILabel alloc] initWithFrame:CGRectMake(0, 0, 210, 20)];
- _titleLabel.text = NSLocalizedString(@"Pull to refresh...",);
- _titleLabel.font = [UIFont boldSystemFontOfSize:14];
- _titleLabel.backgroundColor = [UIColor clearColor];
- _titleLabel.textColor = textColor;
- [self addSubview:_titleLabel];
- }
- return _titleLabel;
- }
- - (UILabel *)subtitleLabel {
- if(!_subtitleLabel) {
- _subtitleLabel = [[UILabel alloc] initWithFrame:CGRectMake(0, 0, 210, 20)];
- _subtitleLabel.font = [UIFont systemFontOfSize:12];
- _subtitleLabel.backgroundColor = [UIColor clearColor];
- _subtitleLabel.textColor = textColor;
- [self addSubview:_subtitleLabel];
- }
- return _subtitleLabel;
- }
- - (UILabel *)dateLabel {
- return self.showsDateLabel ? self.subtitleLabel : nil;
- }
- - (UIColor *)arrowColor {
- return self.arrow.arrowColor; // pass through
- }
- - (UIColor *)textColor {
- return self.titleLabel.textColor;
- }
- - (UIColor *)activityIndicatorViewColor {
- return self.activityIndicatorView.color;
- }
- - (UIActivityIndicatorViewStyle)activityIndicatorViewStyle {
- return self.activityIndicatorView.activityIndicatorViewStyle;
- }
- #pragma mark - Setters
- - (void)setArrowColor:(UIColor *)newArrowColor {
- self.arrow.arrowColor = newArrowColor; // pass through
- [self.arrow setNeedsDisplay];
- }
- - (void)setTitle:(NSString *)title forState:(NTESPullToRefreshState)state {
- if(!title)
- title = @"";
-
- if(state == NTESPullToRefreshStateAll)
- [self.titles replaceObjectsInRange:NSMakeRange(0, 3) withObjectsFromArray:@[title, title, title]];
- else
- [self.titles replaceObjectAtIndex:state withObject:title];
-
- [self setNeedsLayout];
- }
- - (void)setSubtitle:(NSString *)subtitle forState:(NTESPullToRefreshState)state {
- if(!subtitle)
- subtitle = @"";
-
- if(state == NTESPullToRefreshStateAll)
- [self.subtitles replaceObjectsInRange:NSMakeRange(0, 3) withObjectsFromArray:@[subtitle, subtitle, subtitle]];
- else
- [self.subtitles replaceObjectAtIndex:state withObject:subtitle];
-
- [self setNeedsLayout];
- }
- - (void)setCustomView:(UIView *)view forState:(NTESPullToRefreshState)state {
- id viewPlaceholder = view;
-
- if(!viewPlaceholder)
- viewPlaceholder = @"";
-
- if(state == NTESPullToRefreshStateAll)
- [self.viewForState replaceObjectsInRange:NSMakeRange(0, 3) withObjectsFromArray:@[viewPlaceholder, viewPlaceholder, viewPlaceholder]];
- else
- [self.viewForState replaceObjectAtIndex:state withObject:viewPlaceholder];
-
- [self setNeedsLayout];
- }
- - (void)setTextColor:(UIColor *)newTextColor {
- textColor = newTextColor;
- self.titleLabel.textColor = newTextColor;
- self.subtitleLabel.textColor = newTextColor;
- }
- - (void)setActivityIndicatorViewColor:(UIColor *)color {
- self.activityIndicatorView.color = color;
- }
- - (void)setActivityIndicatorViewStyle:(UIActivityIndicatorViewStyle)viewStyle {
- self.activityIndicatorView.activityIndicatorViewStyle = viewStyle;
- }
- #pragma mark -
- - (void)startAnimating{
- switch (self.position) {
- case NTESPullToRefreshPositionTop:
-
- if(fequalzero(self.scrollView.contentOffset.y)) {
- [self.scrollView setContentOffset:CGPointMake(self.scrollView.contentOffset.x, -self.frame.size.height) animated:YES];
- self.wasTriggeredByUser = NO;
- }
- else
- self.wasTriggeredByUser = YES;
-
- break;
- case NTESPullToRefreshPositionBottom:
-
- if((fequalzero(self.scrollView.contentOffset.y) && self.scrollView.contentSize.height < self.scrollView.bounds.size.height)
- || fequal(self.scrollView.contentOffset.y, self.scrollView.contentSize.height - self.scrollView.bounds.size.height)) {
- [self.scrollView setContentOffset:(CGPoint){.y = MAX(self.scrollView.contentSize.height - self.scrollView.bounds.size.height, 0.0f) + self.frame.size.height} animated:YES];
- self.wasTriggeredByUser = NO;
- }
- else
- self.wasTriggeredByUser = YES;
-
- break;
- }
-
- self.state = NTESPullToRefreshStateLoading;
- }
- - (void)stopAnimating {
- self.state = NTESPullToRefreshStateStopped;
-
- switch (self.position) {
- case NTESPullToRefreshPositionTop:
- if(!self.wasTriggeredByUser)
- [self.scrollView setContentOffset:CGPointMake(self.scrollView.contentOffset.x, -self.originalTopInset) animated:YES];
- break;
- case NTESPullToRefreshPositionBottom:
- if(!self.wasTriggeredByUser)
- [self.scrollView setContentOffset:CGPointMake(self.scrollView.contentOffset.x, self.scrollView.contentSize.height - self.scrollView.bounds.size.height + self.originalBottomInset) animated:YES];
- break;
- }
- }
- - (void)setState:(NTESPullToRefreshState)newState {
-
- if(_state == newState)
- return;
-
- NTESPullToRefreshState previousState = _state;
- _state = newState;
-
- [self setNeedsLayout];
- [self layoutIfNeeded];
-
- switch (newState) {
- case NTESPullToRefreshStateAll:
- case NTESPullToRefreshStateStopped:
- [self resetScrollViewContentInset];
- break;
-
- case NTESPullToRefreshStateTriggered:
- break;
-
- case NTESPullToRefreshStateLoading:
- [self setScrollViewContentInsetForLoading];
-
- if(previousState == NTESPullToRefreshStateTriggered && pullToRefreshActionHandler)
- pullToRefreshActionHandler();
-
- break;
- }
- }
- - (void)rotateArrow:(float)degrees hide:(BOOL)hide {
- [UIView animateWithDuration:0.2 delay:0 options:UIViewAnimationOptionAllowUserInteraction animations:^{
- self.arrow.layer.transform = CATransform3DMakeRotation(degrees, 0, 0, 1);
- self.arrow.layer.opacity = !hide;
- //[self.arrow setNeedsDisplay];//ios 4
- } completion:NULL];
- }
- @end
- #pragma mark - NTESPullToRefreshArrow
- @implementation NTESPullToRefreshArrow
- @synthesize arrowColor;
- - (UIColor *)arrowColor {
- if (arrowColor) return arrowColor;
- return [UIColor grayColor]; // default Color
- }
- - (void)drawRect:(CGRect)rect {
- CGContextRef c = UIGraphicsGetCurrentContext();
-
- // the rects above the arrow
- CGContextAddRect(c, CGRectMake(5, 0, 12, 4)); // to-do: use dynamic points
- CGContextAddRect(c, CGRectMake(5, 6, 12, 4)); // currently fixed size: 22 x 48pt
- CGContextAddRect(c, CGRectMake(5, 12, 12, 4));
- CGContextAddRect(c, CGRectMake(5, 18, 12, 4));
- CGContextAddRect(c, CGRectMake(5, 24, 12, 4));
- CGContextAddRect(c, CGRectMake(5, 30, 12, 4));
-
- // the arrow
- CGContextMoveToPoint(c, 0, 34);
- CGContextAddLineToPoint(c, 11, 48);
- CGContextAddLineToPoint(c, 22, 34);
- CGContextAddLineToPoint(c, 0, 34);
- CGContextClosePath(c);
-
- CGContextSaveGState(c);
- CGContextClip(c);
-
- // Gradient Declaration
- CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();
- CGFloat alphaGradientLocations[] = {0, 0.8f};
-
- CGGradientRef alphaGradient = nil;
- if([[[UIDevice currentDevice] systemVersion]floatValue] >= 5){
- NSArray* alphaGradientColors = [NSArray arrayWithObjects:
- (id)[self.arrowColor colorWithAlphaComponent:0].CGColor,
- (id)[self.arrowColor colorWithAlphaComponent:1].CGColor,
- nil];
- alphaGradient = CGGradientCreateWithColors(colorSpace, (__bridge CFArrayRef)alphaGradientColors, alphaGradientLocations);
- }else{
- const CGFloat * components = CGColorGetComponents([self.arrowColor CGColor]);
- size_t numComponents = CGColorGetNumberOfComponents([self.arrowColor CGColor]);
- CGFloat colors[8];
- switch(numComponents){
- case 2:{
- colors[0] = colors[4] = components[0];
- colors[1] = colors[5] = components[0];
- colors[2] = colors[6] = components[0];
- break;
- }
- case 4:{
- colors[0] = colors[4] = components[0];
- colors[1] = colors[5] = components[1];
- colors[2] = colors[6] = components[2];
- break;
- }
- }
- colors[3] = 0;
- colors[7] = 1;
- alphaGradient = CGGradientCreateWithColorComponents(colorSpace,colors,alphaGradientLocations,2);
- }
-
-
- CGContextDrawLinearGradient(c, alphaGradient, CGPointZero, CGPointMake(0, rect.size.height), 0);
-
- CGContextRestoreGState(c);
-
- CGGradientRelease(alphaGradient);
- CGColorSpaceRelease(colorSpace);
- }
- @end
|