Three20软件引擎之TabBar与下拉列表访问数据与刷新
雨松MOMO原创文章如转载,请注明:转载至我的独立域名博客雨松MOMO程序研究院,原文地址:http://www.xuanyusong.com/archives/647
MOMO一直在使用新浪微博,对围脖中拖动下拉刷新的控件比较感兴趣,顺便求个粉,哇咔咔,点击博客网页左侧记得粉我喔。今天制作了一个简单的小例子,好东西一定要和大家分享哦。如下图所示,本节我们实现的是目标:1.在屏幕下方添加TabBar控件,选择不同的控件后刷新不同的资源。2.在屏幕中向下拖动界面时在顶端出现刷新的视图,手放开后开始访问网络下载数据。本节我们访问的网址是Google的Logo图片地址,首次刷新时将访问下载地址,然后将图片资源缓存至本地,再次刷新时先查看缓存中是否有这张图片,如果有则不继续访问下载图片。下图中还有一个小瑕疵,就是顶端视图中刷新的现实内容位英文,不过不要紧后面我会告诉大家如何修改这些文字成中文。
下面开始本节的教学,首先是程序的入口方法,我不做过多的解释,不清楚的朋友请阅读我之前的文章。
AppDelegate.m
#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
注解2:视图控制器,切换TabBar后将进入这个控制器当中。因为本节中TabBar比较简单,所以我将它们都写在了一个控制器当中,通过参数来区分它们。当然它们也可以分开写在不同的控制器当中。最后程序将首先进入TabBarController控制器。
TabBarController.h
#import <Three20/Three20.h> @interface TabBarController : UITabBarController { } @end
#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
MenuViewController.h
#import <Three20/Three20.h> @interface MenuViewController : TTTableViewController { } @end
#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
#import <Three20/Three20.h> #import "Model.h" @class Model; @interface ListDataSource : TTListDataSource { //用于监听下拉列表读取与刷新 Model* _custiom_model; } @end
#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
注解2:在这里刷新UI,它会等待Model类中发送刷新UI的请求,一旦Model中下载数据成功后,调用方法将会在这里刷新UI的内容。这段代码表示绘制列表,包含图片与文字。
Model.h
#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
#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
注解2:requestDidFinishLoad方法表示数据下载完毕后反馈结果时调用,图片资源已经缓存至本地。最后调用[super requsetDidFinishLoad]方法来刷新UI,它也是通知ListDataSource类开始刷新界面。
如果是模拟器的话,图片将被缓存至Library(资源库)->Application Support->Iphone Simulator->5.1(模拟器版本)->Applications->你的 程序->Library->Caches->Three20
如下图所示Google的资源被存在本地。
通过如下方法即可在缓存中获取该对象, 值得注意的时url并不是上图中对应的资源名称,而是下载图片时的地址。
TTURLCache* cacheStore = [TTURLCache sharedCache]; UIImage * image = [cacheStore imageForURL:_url fromDisk:NO];
#import <Three20/Three20.h> @interface CustomDaragRefesh : TTTableViewDragRefreshDelegate { } @end
CustomDaragRefesh.m
用于监听下拉列表所有的事件。
#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中的源码。
修改过的代码
@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愿和 大家好好学习,大家一起进步哈~!!!