您的位置:首页 > 产品设计 > UI/UE

Three20软件引擎之TabBar与下拉列表访问数据与刷新(五)

2012-03-29 17:42 585 查看
Three20软件引擎之TabBar与下拉列表访问数据与刷新

雨松MOMO原创文章如转载,请注明:转载至我的独立域名博客雨松MOMO程序研究院[b],原文地址:http://www.xuanyusong.com/archives/647
[/b]

       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

注解1:表示TabBarController,它时TabBar的控制器,在这里分配TabBar的数量包括选择后显示的视图控制器等。注解2:视图控制器,切换TabBar后将进入这个控制器当中。因为本节中TabBar比较简单,所以我将它们都写在了一个控制器当中,通过参数来区分它们。当然它们也可以分开写在不同的控制器当中。最后程序将首先进入TabBarController控制器。
TabBarController.h#import <Three20/Three20.h>

@interface TabBarController : UITabBarController {
}

@end
TabBarController.m#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#import <Three20/Three20.h>

@interface MenuViewController : TTTableViewController
{
}

@end
MenuViewController.m#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
ListDataSource.m#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#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#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并不是上图中对应的资源名称,而是下载图片时的地址。 TTURLCache* cacheStore = [TTURLCache sharedCache];
UIImage * image = [cacheStore imageForURL:_url fromDisk:NO];
CustomDaragRefesh.h#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愿和 大家好好学习,大家一起进步哈~!!!

下载地址:http://www.xuanyusong.com/archives/647(下载后必需搭建three20环境成功后才能运行~ 因为three20为引用加载,所以程序路径都是我本机的请见谅!或者你可可以将你的Three20路径修改的和我一样就可以直接运行啦,我的路径是:User (用户) -> Share(共享)->Three20)。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息