开源中国iOS客户端学习——(二)下拉刷新特效EGOTableViewPullRefresh

   打开开源中国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 >= 40000 		if ([[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



     本文转自新风作浪 51CTO博客,原文链接:http://blog.51cto.com/duxinfeng/1208695,如需转载请自行联系原作者





  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值