MOMO一直在使用新浪微博,对围脖中拖动下拉刷新的控件比较感兴趣,顺便求个粉,哇咔咔,点击博客网页左侧记得粉我喔。今天制作了一个简单的小例子,好东西一定要和大家分享哦。如下图所示,本节我们实现的是目标:1.在屏幕下方添加TabBar控件,选择不同的控件后刷新不同的资源。2.在屏幕中向下拖动界面时在顶端出现刷新的视图,手放开后开始访问网络下载数据。本节我们访问的网址是Google的Logo图片地址,首次刷新时将访问下载地址,然后将图片资源缓存至本地,再次刷新时先查看缓存中是否有这张图片,如果有则不继续访问下载图片。下图中还有一个小瑕疵,就是顶端视图中刷新的现实内容位英文,不过不要紧后面我会告诉大家如何修改这些文字成中文。
下面开始本节的教学,首先是程序的入口方法,我不做过多的解释,不清楚的朋友请阅读我之前的文章。
AppDelegate.m
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 |
#import "AppDelegate.h" #import "TabBarController.h" #import "MenuViewController.h" #import "TableTestContrller.h" @implementation AppDelegate @synthesize window = _window; - (void)dealloc { [_window release]; [super dealloc]; } - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { TTNavigator* navigator = [TTNavigator navigator]; navigator.persistenceMode = TTNavigatorPersistenceModeAll; navigator.window = [[[UIWindow alloc] initWithFrame:TTScreenBounds()] autorelease]; TTURLMap* map = navigator.URLMap; // Any URL that doesn't match will fall back on this one, and open in the web browser [map from:@"*" toViewController:[TTWebController class]]; //注解1 [map from:@"tt://tabBar" toSharedViewController:[TabBarController class]]; //注解2 [map from:@"tt://menuView/(initMenu:)" toSharedViewController:[MenuViewController class]]; if (![navigator restoreViewControllers]) { [navigator openURLAction:[TTURLAction actionWithURLPath:@"tt://tabBar"]]; } return YES; } @end |
注解1:表示TabBarController,它时TabBar的控制器,在这里分配TabBar的数量包括选择后显示的视图控制器等。
注解2:视图控制器,切换TabBar后将进入这个控制器当中。因为本节中TabBar比较简单,所以我将它们都写在了一个控制器当中,通过参数来区分它们。当然它们也可以分开写在不同的控制器当中。最后程序将首先进入TabBarController控制器。
TabBarController.h
1 2 3 4 5 6 7 8 |
#import <Three20/Three20.h> @interface TabBarController : UITabBarController { } @end |
TabBarController.m
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 |
#import "TabBarController.h" @implementation TabBarController - (void)viewDidLoad { //获取当前屏幕的尺寸 CGSize screen = [[UIScreen mainScreen]bounds].size; //设置TabBar的现实区域 //这里表示位置在屏幕底部并且高度是44 self.tabBar.frame = CGRectMake(0, screen.height - 44, screen.width, 44); //注解1 [self setTabURLs:[NSArray arrayWithObjects:@"tt://menuView/0", @"tt://menuView/1", nil]]; } @end |
注解1:设置Tabbar的数量,数组的长度就是它的数量, @”tt://menyView/0″表示点击第一个TabBar按钮后进入的视图控制器,以此类推。 那么在这里点击按钮后程序将进入MenuViewController。
MenuViewController.h
1 2 3 4 5 6 7 8 9 |
#import <Three20/Three20.h> @interface MenuViewController : TTTableViewController { } @end |
MenuViewController.m
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 |
#import "MenuViewController.h" #import "ListDataSource.h" #import "CustomDaragRefesh.h" @implementation MenuViewController - (id)initMenu:(int)page { if (self = [super init]) { //初始化页面的ID [self setPage:page]; } return self; } - (void)dealloc { [super dealloc]; } -(void)loadView { [super loadView]; //注解1 TTURLCache* cacheStore = [TTURLCache sharedCache]; [cacheStore removeURL:@"http://www.google.com.hk/intl/zh-CN/images/logo_cn.png" fromDisk:YES]; } - (void)setPage:(int)page { //设置标题与TabBar的图片与文字 switch (page) { case 0: self.title = @"雨松MOMO"; self.tabBarItem = [[[UITabBarItem alloc] initWithTitle:self.title image:TTIMAGE(@"bundle://icon0.png") tag:0] autorelease]; break; case 1: self.title = @"RORO娃娃"; self.tabBarItem = [[[UITabBarItem alloc] initWithTitle:self.title image:TTIMAGE(@"bundle://icon1.png") tag:0] autorelease]; break; default: break; } } -(void)createModel { //注解2 self.dataSource = [[[ListDataSource alloc] init] autorelease]; } - (id)createDelegate { //注解3 CustomDaragRefesh *a = [[[CustomDaragRefesh alloc] initWithController:self] autorelease]; return a; } @end |
注解1:访问应用程序的缓存,在这里可以拿到缓存的资源文件。这里表示首次进入该视图控制器时删除之前缓存的资源。下面会详细介绍缓存的机制。
注解2:createModel 方法表示初始化创建模型数据,该方法是系统调用用于初始化数据。为了刷新列表中显示的内容,我们在这里重写了TTListDataSource显示类,所有的内容将在ListDataSource中计算。
注解3:createDelegate方法表示初始化一个委托,它也是由系统调用。这里的代码表示创建一个下拉列表,仅仅只是创建的现实的视图。CustiomDaragRefesh继承于TTTabViewDragRefreshDelegate类,我们在这里监听用户拖动下拉列表的事件。
ListDataSource.h
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
#import <Three20/Three20.h> #import "Model.h" @class Model; @interface ListDataSource : TTListDataSource { //用于监听下拉列表读取与刷新 Model* _custiom_model; } @end |
ListDataSource.m
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 |
#import "ListDataSource.h" @implementation ListDataSource - (id)init{ if (self = [super init]) { //创建Model _custiom_model = [[[Model alloc] init] autorelease]; } return self; } - (void)dealloc { TT_RELEASE_SAFELY(_custiom_model); [super dealloc]; } - (id<TTModel>)model { //注解1 return _custiom_model; } - (void)tableViewDidLoadModel:(UITableView*)tableView { //注解2 NSMutableArray* items = [[[NSMutableArray alloc] init]autorelease]; int count = _custiom_model.images.count; for (int i = 0; i < count; i++) { UIImage * image = [_custiom_model.images objectAtIndex:i]; [items addObject: [TTTableRightImageItem itemWithText: @"M" imageURL:nil defaultImage:image imageStyle:TTSTYLE(rounded) URL:@"tt://tableItemTest"]]; } self.items = items; } @end |
注解1: 在这里重写modle方法,表示设置下拉列表的模型,因为我们需要在Model中实现下载数据的操作。
注解2:在这里刷新UI,它会等待Model类中发送刷新UI的请求,一旦Model中下载数据成功后,调用方法将会在这里刷新UI的内容。这段代码表示绘制列表,包含图片与文字。
Model.h
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
#import <Three20/Three20.h> #import "ListDataSource.h" @interface Model : TTURLRequestModel { //图片 NSMutableArray * _images; //文字 NSMutableArray * _texts; //图片地址 NSString * _url; } @property (nonatomic, assign) NSMutableArray * images; @property (nonatomic, assign) NSMutableArray * texts; @property (nonatomic, assign) NSString * url; @end |
Model.m
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 |
#import "Model.h" @implementation Model @synthesize images = _images; @synthesize texts = _texts; @synthesize url = _url; - (id)init { if (self = [super init]) { self.images = [[NSMutableArray alloc] init]; self.texts = [[NSMutableArray alloc] init]; self.url = @"http://www.google.com.hk/intl/zh-CN/images/logo_cn.png"; } return self; } - (void) dealloc { TT_RELEASE_SAFELY(_images); TT_RELEASE_SAFELY(_texts); TT_RELEASE_SAFELY(_url); [super dealloc]; } - (void)load:(TTURLRequestCachePolicy)cachePolicy more:(BOOL)more { //是否正在下载中 if (!self.isLoading) { UIImage* image = nil; //得到缓存对象 TTURLCache* cacheStore = [TTURLCache sharedCache]; //判断缓存中是否有url指定的资源对象 if ([cacheStore hasDataForKey:[cacheStore keyForURL:_url] expires:3000]) { //直接从缓存中获取对象 image = [cacheStore imageForURL:_url fromDisk:NO]; if (image == nil) { // 图片未能在缓存中获取,尝试在内存中获取图片 image = [UIImage imageWithData:[cacheStore dataForURL:_url]]; } [self.images addObject:image]; //注解1 [self didFinishLoad]; } else { // 图片未能在缓存中找到,删除缓存地址尝试重新下载图片 [cacheStore removeURL:_url fromDisk:YES]; } //如果图片未能获取到,我们开始下载图片 if(image == nil) { //下载请求 TTURLRequest* request = [TTURLRequest requestWithURL: _url delegate: self]; //表示接收图片数据 request.response = [[[TTURLImageResponse alloc] init] autorelease]; //发送异步请求 if(![request send]) { //异步请求未能成功发送,这里需要处理一下 } //资源下载成功后将缓存在本地中。 } } } - (void)requestDidFinishLoad:(TTURLRequest*)request { TTURLCache* cacheStore = [TTURLCache sharedCache]; UIImage * image = [cacheStore imageForURL:_url fromDisk:NO]; //图片资源下载完毕后,后缓存中取得图片资源 if(image != nil) { [self.images addObject:image]; } //注解2 [super requestDidFinishLoad:request]; } @end |
注解1:在视图中下列表时程序将自动调用Load方法,首先在缓存中判断图片资源是否存在,如果缓存中没有该资源,那么根据URL地址开始下载图片资源。didFinishLoad方法表示通知ListDataSource类开始刷新UI。然后会执行ListDataSource类中的tableViewDidLoadModel方法。
注解2:requestDidFinishLoad方法表示数据下载完毕后反馈结果时调用,图片资源已经缓存至本地。最后调用[super requsetDidFinishLoad]方法来刷新UI,它也是通知ListDataSource类开始刷新界面。
如果是模拟器的话,图片将被缓存至Library(资源库)->Application Support->Iphone Simulator->5.1(模拟器版本)->Applications->你的 程序->Library->Caches->Three20
如下图所示Google的资源被存在本地。
通过如下方法即可在缓存中获取该对象, 值得注意的时url并不是上图中对应的资源名称,而是下载图片时的地址。
1 2 3 4 |
TTURLCache* cacheStore = [TTURLCache sharedCache]; UIImage * image = [cacheStore imageForURL:_url fromDisk:NO]; |
CustomDaragRefesh.h
1 2 3 4 5 6 7 8 9 |
#import <Three20/Three20.h> @interface CustomDaragRefesh : TTTableViewDragRefreshDelegate { } @end |
CustomDaragRefesh.m
用于监听下拉列表所有的事件。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 |
#import "CustomDaragRefesh.h" @implementation CustomDaragRefesh - (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath { NSLog(@"点击刷新视图时"); } - (void)scrollViewDidScroll:(UIScrollView*)scrollView { [super scrollViewDidScroll:scrollView]; NSLog(@"拖动刷新视图时"); } - (void)scrollViewDidEndDragging:(UIScrollView*)scrollView willDecelerate:(BOOL)decelerate { [super scrollViewDidEndDragging:scrollView willDecelerate:decelerate]; NSLog(@"拖动刷新视图松手时"); } - (void)modelDidStartLoad:(id<TTModel>)model { NSLog(@"开始下载时"); } - (void)modelDidFinishLoad:(id<TTModel>)model { NSLog(@"下载结束时"); } - (void)model:(id<TTModel>)model didFailLoadWithError:(NSError*)error { NSLog(@"下载失败的错误%@", error); } @end |
最后我们学习文章开头中提到的,如何修改刷新文字。我觉得这里直接修改源码就可以,我查看了源码,感觉这里写的非常不灵活。刷新的文字写在TTTabHeaderDragRefreshView中。如下图所示,刷新的文字已经修改成中文。最后我们在来学习一下Three20的运行机制,编译程序时Three20会把自身所有的.m文件封装成.a文件。我们修改了它的源码,编译时three20会重新生成新的.a文件,所以我们无法进行调试Three20中的源码。
修改过的代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 |
@implementation TTTableHeaderDragRefreshView /////////////////////////////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////////////////////////// #pragma mark - #pragma mark Private /////////////////////////////////////////////////////////////////////////////////////////////////// - (void)showActivity:(BOOL)shouldShow animated:(BOOL)animated { if (shouldShow) { [_activityView startAnimating]; } else { [_activityView stopAnimating]; } [UIView beginAnimations:nil context:nil]; [UIView setAnimationDuration:(animated ? ttkDefaultFastTransitionDuration : 0.0)]; _arrowImage.alpha = (shouldShow ? 0.0 : 1.0); [UIView commitAnimations]; } /////////////////////////////////////////////////////////////////////////////////////////////////// - (void)setImageFlipped:(BOOL)flipped { [UIView beginAnimations:nil context:NULL]; [UIView setAnimationDuration:ttkDefaultFastTransitionDuration]; [_arrowImage layer].transform = (flipped ? CATransform3DMakeRotation(M_PI * 2, 0.0f, 0.0f, 1.0f) : CATransform3DMakeRotation(M_PI, 0.0f, 0.0f, 1.0f)); [UIView commitAnimations]; } /////////////////////////////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////////////////////////// #pragma mark - #pragma mark NSObject /////////////////////////////////////////////////////////////////////////////////////////////////// - (id)initWithFrame:(CGRect)frame { if (self = [super initWithFrame:frame]) { self.autoresizingMask = UIViewAutoresizingFlexibleWidth; _lastUpdatedLabel = [[UILabel alloc] initWithFrame:CGRectMake(0.0f, frame.size.height - 30.0f, frame.size.width, 20.0f)]; _lastUpdatedLabel.autoresizingMask = UIViewAutoresizingFlexibleRightMargin ¦ UIViewAutoresizingFlexibleLeftMargin; _lastUpdatedLabel.font = TTSTYLEVAR(tableRefreshHeaderLastUpdatedFont); _lastUpdatedLabel.textColor = TTSTYLEVAR(tableRefreshHeaderTextColor); _lastUpdatedLabel.shadowColor = TTSTYLEVAR(tableRefreshHeaderTextShadowColor); _lastUpdatedLabel.shadowOffset = TTSTYLEVAR(tableRefreshHeaderTextShadowOffset); _lastUpdatedLabel.backgroundColor = [UIColor clearColor]; _lastUpdatedLabel.textAlignment = UITextAlignmentCenter; [self addSubview:_lastUpdatedLabel]; _statusLabel = [[UILabel alloc] initWithFrame:CGRectMake(0.0f, frame.size.height - 48.0f, frame.size.width, 20.0f )]; _statusLabel.autoresizingMask = UIViewAutoresizingFlexibleRightMargin ¦ UIViewAutoresizingFlexibleLeftMargin; _statusLabel.font = TTSTYLEVAR(tableRefreshHeaderStatusFont); _statusLabel.textColor = TTSTYLEVAR(tableRefreshHeaderTextColor); _statusLabel.shadowColor = TTSTYLEVAR(tableRefreshHeaderTextShadowColor); _statusLabel.shadowOffset = TTSTYLEVAR(tableRefreshHeaderTextShadowOffset); _statusLabel.backgroundColor = [UIColor clearColor]; _statusLabel.textAlignment = UITextAlignmentCenter; [self setStatus:TTTableHeaderDragRefreshPullToReload]; [self addSubview:_statusLabel]; UIImage* arrowImage = TTSTYLEVAR(tableRefreshHeaderArrowImage); _arrowImage = [[UIImageView alloc] initWithFrame:CGRectMake(25.0f, frame.size.height - 60.0f, arrowImage.size.width, arrowImage.size.height)]; _arrowImage.image = arrowImage; [_arrowImage layer].transform = CATransform3DMakeRotation(M_PI, 0.0f, 0.0f, 1.0f); [self addSubview:_arrowImage]; _activityView = [[UIActivityIndicatorView alloc] initWithActivityIndicatorStyle:UIActivityIndicatorViewStyleGray]; _activityView.frame = CGRectMake( 30.0f, frame.size.height - 38.0f, 20.0f, 20.0f ); _activityView.hidesWhenStopped = YES; [self addSubview:_activityView]; } return self; } /////////////////////////////////////////////////////////////////////////////////////////////////// - (void)dealloc { TT_RELEASE_SAFELY(_activityView); TT_RELEASE_SAFELY(_statusLabel); TT_RELEASE_SAFELY(_arrowImage); TT_RELEASE_SAFELY(_lastUpdatedLabel); TT_RELEASE_SAFELY(_lastUpdatedDate); [super dealloc]; } /////////////////////////////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////////////////////////// #pragma mark - #pragma mark Public /////////////////////////////////////////////////////////////////////////////////////////////////// - (void)setUpdateDate:(NSDate*)newDate { if (newDate) { if (_lastUpdatedDate != newDate) { [_lastUpdatedDate release]; } _lastUpdatedDate = [newDate retain]; NSDateFormatter* formatter = [[NSDateFormatter alloc] init]; [formatter setDateStyle:NSDateFormatterShortStyle]; [formatter setTimeStyle:NSDateFormatterShortStyle]; _lastUpdatedLabel.text = [NSString stringWithFormat: TTLocalizedString(@"最后更新: %@", @"The last time the table view was updated."), [formatter stringFromDate:_lastUpdatedDate]]; [formatter release]; } else { _lastUpdatedDate = nil; _lastUpdatedLabel.text = TTLocalizedString(@"Last updated: never", @"The table view has never been updated"); } } /////////////////////////////////////////////////////////////////////////////////////////////////// - (void)setCurrentDate { [self setUpdateDate:[NSDate date]]; } /////////////////////////////////////////////////////////////////////////////////////////////////// - (void)setStatus:(TTTableHeaderDragRefreshStatus)status { switch (status) { case TTTableHeaderDragRefreshReleaseToReload: { [self showActivity:NO animated:NO]; [self setImageFlipped:YES]; _statusLabel.text = TTLocalizedString(@"松开即可刷新...", @"Release the table view to update the contents."); break; } case TTTableHeaderDragRefreshPullToReload: { [self showActivity:NO animated:NO]; [self setImageFlipped:NO]; _statusLabel.text = TTLocalizedString(@"下拉可以刷新...", @"Drag the table view down to update the contents."); break; } case TTTableHeaderDragRefreshLoading: { [self showActivity:YES animated:YES]; [self setImageFlipped:NO]; _statusLabel.text = TTLocalizedString(@"加载中...", @"Updating the contents of a table view."); break; } default: { break; } } } @end |
最后欢迎各位盆友可以和MOMO一起讨论Three20软件开发,如果你觉得看得不清楚,MOMO附带上本章的源码下载,希望大家可以一起学习 哈哈~。哇咔咔~ MOMO愿和 大家好好学习,大家一起进步哈~!!!
- 本文固定链接: https://www.xuanyusong.com/archives/647
- 转载请注明: 雨松MOMO 于 雨松MOMO程序研究院 发表
那个头文件找到了,导入#import 就行了,谢谢啦,继续学习
请问楼主,我也遇到一楼同样的问题,尖括号呗过滤了,是什么意思,纠结
请教一个问题,TabBarController中,[self setTabURLs…..那句代码,在XCode4.4.1中,提示没有这个方法呢?TabBarController继承的UITabBarController,这个controller也没有这个方法,请问是怎么回事啊?
好像是少一个引用头文件
请问具体是哪个头文件呢?我在.h中,这么写的:#import
晕,尖括号被过滤了。在.h中,引入了Three20/Three20.h
是的。
有没有android上面的下拉刷新代码,网上的跟我现在用的这个效果不太好,体验不是很好,如果有的话希望共享一下