開源中國iOS客戶端學習——(二)下拉刷新特效EGOTableViewPullRefresh

 打開開源中國iOS客戶端應用程序第一步就是加載數據,常常咱們在第二次之後打開的時候,咱們界面顯示的是上一次更新的數據,此時咱們想看最新內容就須要去刷新數據加載這些內容,加載須要一個等待過程,如何能讓用戶在等待過程當中不焦急,可以等待這個過程完成,這就須要給用戶一個內心安慰,讓用戶知道該軟件正在很努力很努力的執行本身命令,這就須要咱們爲本身應用程序添加一些特效; git


      開源中國iOS客戶端用到了很多特效,這些特效在當前不少應用軟件中都比較流行,基本上這些特效都屬於第三方類庫,本次想說的是下拉刷新特效,EGOTableViewPullRefresh最開始是在Twitter中使用,最後作了開源,而後不少應用添加這個特效,常做爲加載數據時將等待時間做爲一個動畫來過渡; github

下拉刷新類庫EGOTableViewPullRefresh資源文件下載地址: app

 https://github.com/enormego/EGOTableViewPullRefresh/tree/ 框架


先這個特效的效果圖 函數

   


在EGOTableViewPullRefresh資源文件中有兩個文件,.m和.h文件,還有資源圖片,就是下拉刷新箭頭 學習


資源圖片一共4種色,能夠根據喜愛選用不一樣色的箭頭,只需在EGORefreshTableHeaderView.m文件中修改一下。按照大小尺寸又可分兩種,較大尺寸是用於iPad上使用的。 動畫



針對這些第三方類庫,咱們不必去深刻研究它們內部實現機制原理,只要知道怎麼用就能夠。不過,看一看別人實現原理,學學別人的方法仍是很不錯的,瞭解下人家牛人程序是怎麼寫的; atom


EGORefreshTableHeaderView.h spa

  1. #import <UIKit/UIKit.h>  
  2. #import <QuartzCore/QuartzCore.h>  
  3.   
  4. typedef enum{  
  5.     EGOOPullRefreshPulling = 0,  
  6.     EGOOPullRefreshNormal,  
  7.     EGOOPullRefreshLoading,   
  8. } EGOPullRefreshState;  
  9.   
  10. @protocol EGORefreshTableHeaderDelegate;  
  11. @interface EGORefreshTableHeaderView : UIView {  
  12.       
  13.     id _delegate;  
  14.     EGOPullRefreshState _state;  
  15.   
  16.     UILabel *_lastUpdatedLabel;  
  17.     UILabel *_statusLabel;  
  18.     CALayer *_arrowImage;  
  19.     UIActivityIndicatorView *_activityView;  
  20.       
  21. }  
  22.   
  23. @property(nonatomic,assign) id <EGORefreshTableHeaderDelegate> delegate;  
  24.   
  25. - (id)initWithFrame:(CGRect)frame arrowImageName:(NSString *)arrow textColor:(UIColor *)textColor;  
  26.   
  27. - (void)refreshLastUpdatedDate;  
  28. - (void)egoRefreshScrollViewDidScroll:(UIScrollView *)scrollView;  
  29. - (void)egoRefreshScrollViewDidEndDragging:(UIScrollView *)scrollView;  
  30. - (void)egoRefreshScrollViewDataSourceDidFinishedLoading:(UIScrollView *)scrollView;  
  31.   
  32. @end  
  33. //定義協議方法  
  34. @protocol EGORefreshTableHeaderDelegate  
  35. //下拉的時候調用此方法  
  36. - (void)egoRefreshTableHeaderDidTriggerRefresh:(EGORefreshTableHeaderView*)view;  
  37. //判斷刷新狀態狀況,正在刷新或者是沒刷新  
  38. - (BOOL)egoRefreshTableHeaderDataSourceIsLoading:(EGORefreshTableHeaderView*)view;  
  39. @optional  
  40. //返回刷新時間,回調方法  
  41. - (NSDate*)egoRefreshTableHeaderDataSourceLastUpdated:(EGORefreshTableHeaderView*)view;  
  42. @end  

首先是定義了一個枚舉類型EGOPullRefreshState表示當前咱們操做在哪一種狀態下,有下拉狀態、正常狀態、數據加載狀態;


@protocol EGORefreshTableHeaderDelegate;表示聲明有這個協議,該協議裏面聲明瞭一些方法,只要其餘的類遵循了這個協議(也就是遵循了它的規定),就能夠去實現協議裏面方法,協議裏的方法是留給遵循這個協議的類去實現的,也是留給外部實現接口; .net


EGORefreshTableHeaderView成員變量定義兩個label用於提示下拉過程所處狀態,和顯示的刷新時間。定義的CALayer類對象裝載顯示圖片。UIActivityIndicatorView類對象顯示一個等待動畫;


@property(nonatomic,assign)id <EGORefreshTableHeaderDelegate> delegate;聲明一個協議對象;


接着下面的是EGORefreshTableHeaderView類成員函數,用於實現類庫中下拉刷新的效果;


最後定義了4個協議方法,其中最後一個協議方法爲可選實現;


下面是EGORefreshTableHeaderView.m文件,想說的都在註釋裏


  1. #import "EGORefreshTableHeaderView.h"  
  2.   
  3.   
  4. #define TEXT_COLOR   [UIColor colorWithRed:87.0/255.0 green:108.0/255.0 blue:137.0/255.0 alpha:1.0]  
  5. #define FLIP_ANIMATION_DURATION 0.18f  
  6.   
  7.   
  8. //設置的一個私有接口,只能本類來使用  
  9. @interface EGORefreshTableHeaderView (Private)  
  10. - (void)setState:(EGOPullRefreshState)aState;  
  11. @end  
  12.   
  13. @implementation EGORefreshTableHeaderView  
  14.   
  15. @synthesize delegate=_delegate;  
  16.   
  17. //初始化框架屬性,  
  18. - (id)initWithFrame:(CGRect)frame arrowImageName:(NSString *)arrow textColor:(UIColor *)textColor  {  
  19.     if((self = [super initWithFrame:frame])) {  
  20. //      self.view自動適應bounds的寬度  
  21.         self.autoresizingMask = UIViewAutoresizingFlexibleWidth;  
  22. //        self.view背景色和透明度設置  
  23.         self.backgroundColor = [UIColor colorWithRed:226.0/255.0 green:231.0/255.0 blue:237.0/255.0 alpha:1.0];  
  24.   
  25.         UILabel *label = [[UILabel alloc] initWithFrame:CGRectMake(0.0f, frame.size.height - 30.0f, self.frame.size.width, 20.0f)];  
  26.         label.autoresizingMask = UIViewAutoresizingFlexibleWidth;  
  27.         label.font = [UIFont systemFontOfSize:12.0f];  
  28.         label.textColor = textColor;  
  29. //        label文本陰影顏色  
  30.         label.shadowColor = [UIColor colorWithWhite:0.9f alpha:1.0f];  
  31.         label.shadowOffset = CGSizeMake(0.0f, 1.0f);  
  32.         label.backgroundColor = [UIColor clearColor];  
  33.         label.textAlignment = UITextAlignmentCenter;  
  34.         [self addSubview:label];  
  35.         _lastUpdatedLabel=label;  
  36.         [label release];  
  37.           
  38.         label = [[UILabel alloc] initWithFrame:CGRectMake(0.0f, frame.size.height - 48.0f, self.frame.size.width, 20.0f)];  
  39.         label.autoresizingMask = UIViewAutoresizingFlexibleWidth;  
  40.         label.font = [UIFont boldSystemFontOfSize:13.0f];  
  41.         label.textColor = textColor;  
  42.         label.shadowColor = [UIColor colorWithWhite:0.9f alpha:1.0f];  
  43.         label.shadowOffset = CGSizeMake(0.0f, 1.0f);  
  44.         label.backgroundColor = [UIColor clearColor];  
  45.         label.textAlignment = UITextAlignmentCenter;  
  46.         [self addSubview:label];  
  47.         _statusLabel=label;  
  48.         [label release];  
  49.           
  50.         CALayer *layer = [CALayer layer];  
  51.         layer.frame = CGRectMake(25.0f, frame.size.height - 65.0f, 30.0f, 55.0f);  
  52. //        設置layer在view上以某種形式適應  
  53.         layer.contentsGravity = kCAGravityResizeAspect;  
  54.         layer.contents = (id)[UIImage imageNamed:arrow].CGImage;  
  55.           
  56. //        判斷設備版本,由於一些iOS特性是在最後新增的,要求設備配置高一些,因此作一下判斷  
  57. #if __IPHONE_OS_VERSION_MAX_ALLOWED >= 40000  
  58.         if ([[UIScreen mainScreen] respondsToSelector:@selector(scale)]) {  
  59.             layer.contentsScale = [[UIScreen mainScreen] scale];  
  60.         }  
  61. #endif  
  62.           
  63.         [[self layer] addSublayer:layer];  
  64.         _arrowImage=layer;  
  65.           
  66.         UIActivityIndicatorView *view = [[UIActivityIndicatorView alloc] initWithActivityIndicatorStyle:UIActivityIndicatorViewStyleGray];  
  67.         view.frame = CGRectMake(25.0f, frame.size.height - 38.0f, 20.0f, 20.0f);  
  68.         [self addSubview:view];  
  69.         _activityView = view;  
  70.         [view release];  
  71.           
  72.           
  73.         [self setState:EGOOPullRefreshNormal];  
  74.           
  75.     }  
  76.       
  77.     return self;  
  78.       
  79. }  
  1. //初始化當前視圖的frame  
  2. - (id)initWithFrame:(CGRect)frame  {  
  3.   return [self initWithFrame:frame arrowImageName:@"blueArrow.png" textColor:TEXT_COLOR];  
  4. }  
  5.   
  6. #pragma mark -  
  7. #pragma mark Setters  
  8.   
  9. //獲取最後一次更新的時間  
  10. - (void)refreshLastUpdatedDate {  
  11.       
  12.     if ([_delegate respondsToSelector:@selector(egoRefreshTableHeaderDataSourceLastUpdated:)]) {  
  13.           
  14.         NSDate *date = [_delegate egoRefreshTableHeaderDataSourceLastUpdated:self];  
  15. //      NSDateFormatter實例建立字符串,來表示NSDate和NSCalendarDate對象,已預訂格式化字符串輸出    
  16.         [NSDateFormatter setDefaultFormatterBehavior:NSDateFormatterBehaviorDefault];  
  17.         NSDateFormatter *dateFormatter = [[[NSDateFormatter alloc] init] autorelease];  
  18. //        設置日期輸出格式  
  19.         [dateFormatter setDateStyle:NSDateFormatterShortStyle];  
  20. //        設置時間顯示格式  
  21.         [dateFormatter setTimeStyle:NSDateFormatterShortStyle];  
  22.   
  23. //      _lastUpdatedLabel.text = [NSString stringWithFormat:@"Last Updated: %@", [dateFormatter stringFromDate:date]];  
  24.         _lastUpdatedLabel.text = [NSString stringWithFormat:@"最後更新: %@", [dateFormatter stringFromDate:date]];  
  25. //        存儲_lastUpdatedLabel.text內容,放到字典中  
  26.         [[NSUserDefaults standardUserDefaults] setObject:_lastUpdatedLabel.text forKey:@"EGORefreshTableView_LastRefresh"];  
  27. //        將NSUserDefaults存儲數據放到磁盤  
  28.         [[NSUserDefaults standardUserDefaults] synchronize];  
  29.           
  30.     } else {  
  31.           
  32.         _lastUpdatedLabel.text = nil;  
  33.           
  34.     }  
  35.   
  36. }  
  1. - (void)setState:(EGOPullRefreshState)aState{  
  2.       
  3.     switch (aState) {  
  4.             /*觸摸屏幕下拉狀態*/  
  5.         case EGOOPullRefreshPulling:  
  6.               
  7. //          _statusLabel.text = NSLocalizedString(@"Release to refresh...", @"Release to refresh status");  
  8.             _statusLabel.text = @"鬆開便可刷新";  
  9. //            設置下拉刷新過程,箭頭的圖片的一個動畫過程  
  10.             [CATransaction begin];  
  11. //            動畫時間  
  12.             [CATransaction setAnimationDuration:FLIP_ANIMATION_DURATION];  
  13. //            下拉刷新箭頭一個翻轉過程,(M_PI / 180.0)是角度轉換爲弧度  
  14.               
  15.             _arrowImage.transform = CATransform3DMakeRotation((M_PI / 180.0) * 180.0f, 0.0f, 0.0f, 1.0f);  
  16. //            動畫結束  
  17.             [CATransaction commit];  
  18.               
  19.             break;  
  20.             /*剛開始觸摸屏幕準備下拉的時候的狀態*/  
  21.         case EGOOPullRefreshNormal:  
  22.               
  23.             if (_state == EGOOPullRefreshPulling) {  
  24.                 [CATransaction begin];  
  25.                 [CATransaction setAnimationDuration:FLIP_ANIMATION_DURATION];  
  26.                 _arrowImage.transform = CATransform3DIdentity;  
  27.                 [CATransaction commit];  
  28.             }  
  29.               
  30. //          _statusLabel.text = NSLocalizedString(@"Pull down to refresh...", @"Pull down to refresh status");  
  31.             _statusLabel.text = @"下拉能夠刷新";  
  32.             [_activityView stopAnimating];  
  33.             [CATransaction begin];  
  34. //            由於下拉刷新完成好就不須要下拉動畫,此時_activityView動畫顯示  
  35. //            顯示事物關閉動畫效果 kCFBooleanTrue關閉 kCFBooleanFalse開啓  
  36.             [CATransaction setValue:(id)kCFBooleanTrue forKey:kCATransactionDisableActions];   
  37.             _arrowImage.hidden = NO;  
  38.             _arrowImage.transform = CATransform3DIdentity;  
  39.             [CATransaction commit];  
  40. //          更新下時間  
  41.             [self refreshLastUpdatedDate];  
  42.               
  43.             break;  
  44.             /*觸摸手指鬆開,完成下拉操做的狀態*/  
  45.         case EGOOPullRefreshLoading:  
  46.               
  47. //          _statusLabel.text = NSLocalizedString(@"Loading...", @"Loading Status");  
  48.             _statusLabel.text = @"加載中";  
  49.             [_activityView startAnimating];  
  50.             [CATransaction begin];  
  51.             [CATransaction setValue:(id)kCFBooleanTrue forKey:kCATransactionDisableActions];   
  52.             _arrowImage.hidden = YES;  
  53.             [CATransaction commit];  
  54.               
  55.             break;  
  56.         default:  
  57.             break;  
  58.     }  
  59.       
  60.     _state = aState;  
  61. }  
  1. #pragma mark -  
  2. #pragma mark ScrollView Methods  
  3.   
  4. - (void)egoRefreshScrollViewDidScroll:(UIScrollView *)scrollView {    
  5.       
  6.     if (_state == EGOOPullRefreshLoading) {  
  7.           
  8.         CGFloat offset = MAX(scrollView.contentOffset.y * -1, 0);  
  9.         offset = MIN(offset, 60);  
  10.         scrollView.contentInset = UIEdgeInsetsMake(offset, 0.0f, 0.0f, 0.0f);  
  11.           
  12.     } else if (scrollView.isDragging) {  
  13.           
  14.         BOOL _loading = NO;  
  15.         if ([_delegate respondsToSelector:@selector(egoRefreshTableHeaderDataSourceIsLoading:)]) {  
  16.             _loading = [_delegate egoRefreshTableHeaderDataSourceIsLoading:self];  
  17.         }  
  18.           
  19.         if (_state == EGOOPullRefreshPulling && scrollView.contentOffset.y > -65.0f && scrollView.contentOffset.y < 0.0f && !_loading) {  
  20.             [self setState:EGOOPullRefreshNormal];  
  21.         } else if (_state == EGOOPullRefreshNormal && scrollView.contentOffset.y < -65.0f && !_loading) {  
  22.             [self setState:EGOOPullRefreshPulling];  
  23.         }  
  24. //      設置下拉屬性scrollView框架恢復初始位置  
  25.         if (scrollView.contentInset.top != 0) {  
  26. //        A UIEdgeInsets struct whose top, left, bottom, and right fields are all set to the value 0.  
  27.             scrollView.contentInset = UIEdgeInsetsZero;  
  28.         }  
  29.           
  30.     }  
  31.       
  32. }  
  33.   
  34. - (void)egoRefreshScrollViewDidEndDragging:(UIScrollView *)scrollView {  
  35.       
  36.     BOOL _loading = NO;  
  37.     if ([_delegate respondsToSelector:@selector(egoRefreshTableHeaderDataSourceIsLoading:)]) {  
  38.         _loading = [_delegate egoRefreshTableHeaderDataSourceIsLoading:self];  
  39.     }  
  40.       
  41.     if (scrollView.contentOffset.y <= - 65.0f && !_loading) {  
  42.           
  43.         if ([_delegate respondsToSelector:@selector(egoRefreshTableHeaderDidTriggerRefresh:)]) {  
  44.             [_delegate egoRefreshTableHeaderDidTriggerRefresh:self];  
  45.         }  
  46.           
  47.         [self setState:EGOOPullRefreshLoading];  
  48.         [UIView beginAnimations:nil context:NULL];  
  49.         [UIView setAnimationDuration:0.2];  
  50.         scrollView.contentInset = UIEdgeInsetsMake(60.0f, 0.0f, 0.0f, 0.0f);  
  51.         [UIView commitAnimations];  
  52.           
  53.     }  
  54.       
  55. }  
  56. //數據加載完成後調用此方法  
  57. - (void)egoRefreshScrollViewDataSourceDidFinishedLoading:(UIScrollView *)scrollView {     
  58.       
  59.     [UIView beginAnimations:nil context:NULL];  
  60.     [UIView setAnimationDuration:.3];  
  61. //    數據加載完成後,scrollView恢復位置大小  
  62.     [scrollView setContentInset:UIEdgeInsetsMake(0.0f, 0.0f, 0.0f, 0.0f)];  
  63.     [UIView commitAnimations];  
  64. //  數據加載完成,  
  65.     [self setState:EGOOPullRefreshNormal];  
  66.   
  67. }  
  1. #pragma mark -  
  2. #pragma mark Dealloc  
  3.   
  4. - (void)dealloc {  
  5.       
  6.     _delegate=nil;  
  7.     _activityView = nil;  
  8.     _statusLabel = nil;  
  9.     _arrowImage = nil;  
  10.     _lastUpdatedLabel = nil;  
  11.     [super dealloc];  
  12. }  
  13.   
  14.   
  15. @end  


當咱們想使用這個下拉刷新類庫的時候,在使用類裏聲明這個協議<EGORefreshTableHeaderDelegate>,把當前類self交付給下拉刷新庫的協議對象,也就是xx.delegate=self;

怎樣讓其餘類來使用這裏面效果,這時咱們就能夠委託另外一個類來實現協議的方法。

選中一個協議方法,右鍵選擇Jump to Definition就能夠看到哪些類被委託了,怎樣使用了這個類的協議方法:


正在學習過程當中,錯誤之處請指正,歡迎交流,共同窗習;
相關文章
相關標籤/搜索