開源中國iOS用戶端學習——(二)下拉重新整理特效EGOTableViewPullRefresh

來源:互聯網
上載者:User

       開啟開源中國iOS用戶端應用程式第一步就是載入資料,經常我們在第二次以後開啟的時候,我們介面顯示的是上一次更新的資料,此時我們想看最新內容就需要去重新整理資料載入這些內容,載入需要一個等待過程,如何能讓使用者在等待過程中不焦急,能夠等待這個過程完成,這就需要給使用者一個心裡安慰,讓使用者知道該軟體正在很努力很努力的執行自己命令,這就需要我們為自己應用程式添加一些特效;


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

下拉重新整理類庫EGOTableViewPullRefresh資源檔:

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


先這個特效的

  

在EGOTableViewPullRefresh資源檔中有兩個檔案,.m和.h檔案,還有資源圖片,就是下拉重新整理箭頭


資源圖片一共4種色,可以根據喜好選用不同色的箭頭,只需在EGORefreshTableHeaderView.m檔案中修改一下。按照大小尺寸又可分兩種,較大尺寸是用於iPad上使用的。



針對這些第三方類庫,我們沒必要去深入研究它們內部實現機制原理,只要知道怎麼用就可以。不過,看一看別人實現原理,學學別人的方法還是很不錯的,瞭解下人家牛人程式是怎麼寫的;


EGORefreshTableHeaderView.h

#import <UIKit/UIKit.h>#import <QuartzCore/QuartzCore.h>typedef enum{EGOOPullRefreshPulling = 0,EGOOPullRefreshNormal,EGOOPullRefreshLoading,} EGOPullRefreshState;@protocol EGORefreshTableHeaderDelegate;@interface EGORefreshTableHeaderView : UIView {id _delegate;EGOPullRefreshState _state;UILabel *_lastUpdatedLabel;UILabel *_statusLabel;CALayer *_arrowImage;UIActivityIndicatorView *_activityView;}@property(nonatomic,assign) id <EGORefreshTableHeaderDelegate> delegate;- (id)initWithFrame:(CGRect)frame arrowImageName:(NSString *)arrow textColor:(UIColor *)textColor;- (void)refreshLastUpdatedDate;- (void)egoRefreshScrollViewDidScroll:(UIScrollView *)scrollView;- (void)egoRefreshScrollViewDidEndDragging:(UIScrollView *)scrollView;- (void)egoRefreshScrollViewDataSourceDidFinishedLoading:(UIScrollView *)scrollView;@end//定義協議方法@protocol EGORefreshTableHeaderDelegate//下拉的時候調用此方法- (void)egoRefreshTableHeaderDidTriggerRefresh:(EGORefreshTableHeaderView*)view;//判斷重新整理狀態情況,正在重新整理或者是沒重新整理- (BOOL)egoRefreshTableHeaderDataSourceIsLoading:(EGORefreshTableHeaderView*)view;@optional//返回重新整理時間,回調方法- (NSDate*)egoRefreshTableHeaderDataSourceLastUpdated:(EGORefreshTableHeaderView*)view;@end


首先是定義了一個枚舉類型EGOPullRefreshState表示當前我們操作在哪種狀態下,有下拉狀態、正常狀態、資料載入狀態;

@protocol EGORefreshTableHeaderDelegate;表示聲明有這個協議,該協議裡面聲明了一些方法,只要其他的類遵循了這個協議(也就是遵循了它的規定),就可以去實現協議裡面方法,協議裡的方法是留給遵循這個協議的類去實現的,也是留給外部實現介面;


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


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


接著下面的是EGORefreshTableHeaderView類成員函數,用於實作類別庫中下拉重新整理的效果;


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


下面是EGORefreshTableHeaderView.m檔案,想說的都在注釋裡

#import "EGORefreshTableHeaderView.h"#define TEXT_COLOR [UIColor colorWithRed:87.0/255.0 green:108.0/255.0 blue:137.0/255.0 alpha:1.0]#define FLIP_ANIMATION_DURATION 0.18f//設定的一個私人介面,只能本類來使用@interface EGORefreshTableHeaderView (Private)- (void)setState:(EGOPullRefreshState)aState;@end@implementation EGORefreshTableHeaderView@synthesize delegate=_delegate;//初始化架構屬性,- (id)initWithFrame:(CGRect)frame arrowImageName:(NSString *)arrow textColor:(UIColor *)textColor  {    if((self = [super initWithFrame:frame])) {//self.view自動適應bounds的寬度self.autoresizingMask = UIViewAutoresizingFlexibleWidth;//        self.view背景色和透明度設定self.backgroundColor = [UIColor colorWithRed:226.0/255.0 green:231.0/255.0 blue:237.0/255.0 alpha:1.0];UILabel *label = [[UILabel alloc] initWithFrame:CGRectMake(0.0f, frame.size.height - 30.0f, self.frame.size.width, 20.0f)];label.autoresizingMask = UIViewAutoresizingFlexibleWidth;label.font = [UIFont systemFontOfSize:12.0f];label.textColor = textColor;//        label文本陰影顏色label.shadowColor = [UIColor colorWithWhite:0.9f alpha:1.0f];label.shadowOffset = CGSizeMake(0.0f, 1.0f);label.backgroundColor = [UIColor clearColor];label.textAlignment = UITextAlignmentCenter;[self addSubview:label];_lastUpdatedLabel=label;[label release];label = [[UILabel alloc] initWithFrame:CGRectMake(0.0f, frame.size.height - 48.0f, self.frame.size.width, 20.0f)];label.autoresizingMask = UIViewAutoresizingFlexibleWidth;label.font = [UIFont boldSystemFontOfSize:13.0f];label.textColor = textColor;label.shadowColor = [UIColor colorWithWhite:0.9f alpha:1.0f];label.shadowOffset = CGSizeMake(0.0f, 1.0f);label.backgroundColor = [UIColor clearColor];label.textAlignment = UITextAlignmentCenter;[self addSubview:label];_statusLabel=label;[label release];CALayer *layer = [CALayer layer];layer.frame = CGRectMake(25.0f, frame.size.height - 65.0f, 30.0f, 55.0f);//        設定layer在view上以某種形式適應layer.contentsGravity = kCAGravityResizeAspect;layer.contents = (id)[UIImage imageNamed:arrow].CGImage;//        判斷裝置版本,因為一些iOS特性是在最後新增的,要求裝置配置高一些,所以做一下判斷#if __IPHONE_OS_VERSION_MAX_ALLOWED >= 40000if ([[UIScreen mainScreen] respondsToSelector:@selector(scale)]) {layer.contentsScale = [[UIScreen mainScreen] scale];}#endif[[self layer] addSublayer:layer];_arrowImage=layer;UIActivityIndicatorView *view = [[UIActivityIndicatorView alloc] initWithActivityIndicatorStyle:UIActivityIndicatorViewStyleGray];view.frame = CGRectMake(25.0f, frame.size.height - 38.0f, 20.0f, 20.0f);[self addSubview:view];_activityView = view;[view release];[self setState:EGOOPullRefreshNormal];    }    return self;}
//初始化當前視圖的frame- (id)initWithFrame:(CGRect)frame  {  return [self initWithFrame:frame arrowImageName:@"blueArrow.png" textColor:TEXT_COLOR];}#pragma mark -#pragma mark Setters//擷取最後一次更新的時間- (void)refreshLastUpdatedDate {if ([_delegate respondsToSelector:@selector(egoRefreshTableHeaderDataSourceLastUpdated:)]) {NSDate *date = [_delegate egoRefreshTableHeaderDataSourceLastUpdated:self];//NSDateFormatter執行個體建立字串,來表示NSDate和NSCalendarDate對象,已預訂格式化字串輸出  [NSDateFormatter setDefaultFormatterBehavior:NSDateFormatterBehaviorDefault];NSDateFormatter *dateFormatter = [[[NSDateFormatter alloc] init] autorelease];//        設定日期輸出格式[dateFormatter setDateStyle:NSDateFormatterShortStyle];//        設定時間顯示格式[dateFormatter setTimeStyle:NSDateFormatterShortStyle];//_lastUpdatedLabel.text = [NSString stringWithFormat:@"Last Updated: %@", [dateFormatter stringFromDate:date]];        _lastUpdatedLabel.text = [NSString stringWithFormat:@"最後更新: %@", [dateFormatter stringFromDate:date]];//        儲存_lastUpdatedLabel.text內容,放到字典中[[NSUserDefaults standardUserDefaults] setObject:_lastUpdatedLabel.text forKey:@"EGORefreshTableView_LastRefresh"];//        將NSUserDefaults儲存資料放到磁碟[[NSUserDefaults standardUserDefaults] synchronize];} else {_lastUpdatedLabel.text = nil;}}
- (void)setState:(EGOPullRefreshState)aState{switch (aState) {            /*觸控螢幕幕下拉狀態*/case EGOOPullRefreshPulling://_statusLabel.text = NSLocalizedString(@"Release to refresh...", @"Release to refresh status");            _statusLabel.text = @"鬆開即可重新整理";//            設定下拉重新整理過程,箭頭的圖片的一個動畫過程[CATransaction begin];//            動畫時間[CATransaction setAnimationDuration:FLIP_ANIMATION_DURATION];//            下拉重新整理箭頭一個翻轉過程,(M_PI / 180.0)是角度轉換為弧度            _arrowImage.transform = CATransform3DMakeRotation((M_PI / 180.0) * 180.0f, 0.0f, 0.0f, 1.0f);//            動畫結束[CATransaction commit];break;            /*剛開始觸控螢幕幕準備下拉的時候的狀態*/case EGOOPullRefreshNormal:if (_state == EGOOPullRefreshPulling) {[CATransaction begin];[CATransaction setAnimationDuration:FLIP_ANIMATION_DURATION];_arrowImage.transform = CATransform3DIdentity;[CATransaction commit];}//_statusLabel.text = NSLocalizedString(@"Pull down to refresh...", @"Pull down to refresh status");            _statusLabel.text = @"下拉可以重新整理";[_activityView stopAnimating];[CATransaction begin];//            因為下拉重新整理完成好就不需要下拉動畫,此時_activityView動畫顯示//            顯示事物關閉動畫效果 kCFBooleanTrue關閉 kCFBooleanFalse開啟[CATransaction setValue:(id)kCFBooleanTrue forKey:kCATransactionDisableActions]; _arrowImage.hidden = NO;_arrowImage.transform = CATransform3DIdentity;[CATransaction commit];//更新下時間[self refreshLastUpdatedDate];break;            /*觸摸手指鬆開,完成下拉操作的狀態*/case EGOOPullRefreshLoading://_statusLabel.text = NSLocalizedString(@"Loading...", @"Loading Status");            _statusLabel.text = @"載入中";[_activityView startAnimating];[CATransaction begin];[CATransaction setValue:(id)kCFBooleanTrue forKey:kCATransactionDisableActions]; _arrowImage.hidden = YES;[CATransaction commit];break;default:break;}_state = aState;}
#pragma mark -#pragma mark ScrollView Methods- (void)egoRefreshScrollViewDidScroll:(UIScrollView *)scrollView {if (_state == EGOOPullRefreshLoading) {CGFloat offset = MAX(scrollView.contentOffset.y * -1, 0);offset = MIN(offset, 60);scrollView.contentInset = UIEdgeInsetsMake(offset, 0.0f, 0.0f, 0.0f);} else if (scrollView.isDragging) {BOOL _loading = NO;if ([_delegate respondsToSelector:@selector(egoRefreshTableHeaderDataSourceIsLoading:)]) {_loading = [_delegate egoRefreshTableHeaderDataSourceIsLoading:self];}if (_state == EGOOPullRefreshPulling && scrollView.contentOffset.y > -65.0f && scrollView.contentOffset.y < 0.0f && !_loading) {[self setState:EGOOPullRefreshNormal];} else if (_state == EGOOPullRefreshNormal && scrollView.contentOffset.y < -65.0f && !_loading) {[self setState:EGOOPullRefreshPulling];}//設定下拉屬性scrollView架構恢複初始位置if (scrollView.contentInset.top != 0) {//        A UIEdgeInsets struct whose top, left, bottom, and right fields are all set to the value 0.scrollView.contentInset = UIEdgeInsetsZero;}}}- (void)egoRefreshScrollViewDidEndDragging:(UIScrollView *)scrollView {BOOL _loading = NO;if ([_delegate respondsToSelector:@selector(egoRefreshTableHeaderDataSourceIsLoading:)]) {_loading = [_delegate egoRefreshTableHeaderDataSourceIsLoading:self];}if (scrollView.contentOffset.y <= - 65.0f && !_loading) {if ([_delegate respondsToSelector:@selector(egoRefreshTableHeaderDidTriggerRefresh:)]) {[_delegate egoRefreshTableHeaderDidTriggerRefresh:self];}[self setState:EGOOPullRefreshLoading];[UIView beginAnimations:nil context:NULL];[UIView setAnimationDuration:0.2];scrollView.contentInset = UIEdgeInsetsMake(60.0f, 0.0f, 0.0f, 0.0f);[UIView commitAnimations];}}//資料載入完成後調用此方法- (void)egoRefreshScrollViewDataSourceDidFinishedLoading:(UIScrollView *)scrollView {[UIView beginAnimations:nil context:NULL];[UIView setAnimationDuration:.3];//    資料載入完成後,scrollView恢複位置大小[scrollView setContentInset:UIEdgeInsetsMake(0.0f, 0.0f, 0.0f, 0.0f)];[UIView commitAnimations];//資料載入完成,[self setState:EGOOPullRefreshNormal];}
#pragma mark -#pragma mark Dealloc- (void)dealloc {_delegate=nil;_activityView = nil;_statusLabel = nil;_arrowImage = nil;_lastUpdatedLabel = nil;    [super dealloc];}@end


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

怎樣讓其他類來使用這裡面效果,這時我們就可以委託另一個類來實現協議的方法。

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

正在學習過程中,錯誤之處請指正,歡迎交流,共同學習;

歡迎轉載分享,請註明出處http://blog.csdn.net/duxinfeng2010

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.