`

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

 
阅读更多

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

注解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愿和 大家好好学习,大家一起进步哈~!!!



(下载后必需搭建three20环境成功后才能运行~ 因为three20为引用加载,所以程序路径都是我本机的请见谅!或者你可可以将你的Three20路径修改的和我一样就可以直接运行啦,我的路径是:User (用户) -> Share(共享)->Three20)。







分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics