Cover Flow编程1118

来源:互联网 发布:dll文件恢复软件 编辑:程序博客网 时间:2024/05/01 08:21

http://supershll.blog.163.com/blog/static/3707043620121269379367/


第十一章 Cover Flow编程

虽然Cover Flow并未正式包含在iPhone SDK中,但它仍然是iPhone体验中最优秀的特性之一。使用Cover Flow能为用户提供极为出色的视觉选择,这一点令标准的滚动列表望尘莫及。本章将介绍Cover Flow,并展示如何在应用程序中使用它。

11.1 UICoverFlowLayer类
虽然正式的SDK中未包含UIConverFlowLayer,但它仍然是标准的UIKit。通过Steve Nygard的类转储(class-dump)(www.codethecode.com/projects/class-dump/),能从UIKit框架中提取UICoverFlowLayer头文件,如代码清单11-1所示。在Mach-O文件的Obj-C程序中生成类声明便可启动类转储。

代码清单11-1 UICoverFlowLayer.h类头文件
。。。(说明)

以上代码说明,UICoverFlowLayer类定义的是图层,而不是视图。图层是抽象呈现类,存在于每个UIView对象中,它还为这些视图提供内部画布。因此,如果你要使用此类,需要将它包含在可用的视图中。以下部分具体说明其实现方法。

11.2 构建Cover Flow视图
在开始处理Cover Flow之前,需要在UIView中插入UICoverFlowLayer实例。把图层放入视图就使Cover Flow技术成为了标准的UIKit术语,然后便可在本书中使用UIView类进行开发了。为此,你仅需创建视图和分配图层。然而,为了让视图正常地显示和工作,你还需要额外执行一些步骤。
这些步骤定制用户与Cover Flow交互的方式。用户在视图中触摸、拖动、双击时,Cover Flow视图需要对此做出正确的响应。为此,视图必须发送dragFlow:atPoint:消息,以处理与Cover Flow图层的触摸和拖动的交互过程。
双击处理提出了另一个难题。Cover Flow并未针对双击实现任何标准的响应,然而,你缺希望应用程序能识别此交互过程,并对此执行一些合理的响应。按照我设计的UIView类,你就可以设置遵守CoverFlowHost协议的主应用程序。当视图截取双击操作时,就调用主应用程序的doubleTapCallback方法。这样,用户在所选择的封面上执行双击操作时,包含Cover Flow视图的视图控制器就能对此做出响应。
封面翻转(cover flipping)是指Cover Flow图像翻开以显示第二个视图(flipSelectedCover)时而采取的一种交互方式。通常,你可以使用双击反馈,或者使用封面翻转。但是,请确定只选取一种方式,如果同时实现两种方式,就会引发两种交互方式的无谓竞争,同时,你也许无法控制调用哪种响应方式。实现方法如代码清单11-2所示。

说明:本书示例代码中有关本章的完整项目,请参考http://ericasadun.com

代码清单11-2 构建Cover Flow视图
#import <UIKit/UIKit.h>
#import "UICoverFlowLayer.h"
@protocol CoverFlowHost <NSObject>
- (void)doubleTapCallback;
@end

@interface CoverFlowView:UIView {
 id <CoverFlowHost> host;
 id info;
 UICoverFlowLayer *cfLayer;
 UILabel *label;
}

- (CoverFlowView *)initWithFrame:(CGRect)aFrame andCount:(int)aCount;
- (void)tick;
- (void)setHost:(id)anObject;
- (void)flipSelectedCover;
- (UILabel *)label;
- (UICoverFlowLayer *)cfLayer;
@end

@implementation CoverFlowView
- (CoverFlowView *)initWithFrame:(CGRect)aRect andCount:(int)count
{
 self=[super initWithFrame:aRect];
 cfLayer=[[UICoverFlowLayer alloc] initWithFrame:[[UIScreen mainScreen] bounds] numberOfCovers:count];
 [[self layer] addSublayer:cfLayer];

 //Add the placeholder (image stand-in) layer
 CGRect phrect=CGRectMake(0.0f,0.0f,200.0f,200.0f);
 UIImageView *phimg=[[UIImageView alloc] initWithFrame:phrect];
 [cfLayer setPlaceholderImage:[phimg layer]];

 //Add its info (label) layer
 label=[[UILabel alloc] init];
 [label setTextAlignment:UITextAlignmentCenter];
 [label setFont:[UIFont boldSystemFontOfSize:20.0f]];
 [label setBackgroundColor:[UIColor colorWithRed:0.0f green:0.0f blue:0.0f alpha:0.0f]];
 [label setTextColor:[UIColor colorWithRed:1.0f green:1.0f blue:1.0f alpha:0.75f]];
 [label setNumberOfLines:2];
 [label setLineBreakMode:UILineBreakModeWordWrap];
 [cfLayer setInfoLayer:[label layer]];

 return self;
}

- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
 UITouch *touch=[touches anyObject];
 CGPoint pt=[touch locationInView:self];
 [cfLayer dragFlow:0 atPoint:pt];
}

- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event
{
 UITouch *touch=[touches anyObject];
 CGPoint pt=[touch locationInView:self];
 [cfLayer dragFlow:1 atPoint:pt];
}

- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event
{
 UITouch *touch=[touches anyObject];
 CGPoint pt=[touch locationInView:self];

 if ([touch tapCount]==2)
 {
  if (host) [host doubleTapCallback];
  return;
 }

 [cfLayer drawFlow:2 atPoint:pt];
}

- (void)flipSelectedCover
{
 [cfLayer flipSelectedCover];
}

- (BOOL)ignoresMouseEvents {return NO;}
- (void)tick {[cfLayer displayTick];}
- (void)setHost:(id)anObject {host=anObject;}
- (UILabel *)label {return label;}
- (UICoverFlowLayer *)cfLayer {return cfLayer;}
@end


11.3 构建Cover Flow视图控制器
建立CoverFlowView类之后,你就可以向任何视图控制器中添加此视图。让一切正常运行的诀窍在于核对几个计划框。为了让Cover Flow呈现最佳的工作状态,你需要采取以下措施。
1)隐藏应用程序状态栏。Cover Flow应用程序应该全屏运行,而不应出现令人分心的状态栏。隐藏状态栏的方式是调用[[UIApplication sharedApplication] setStatusBarHidden:YES]。
2)分配和初始化视图。你必须提前知道将要使用的封面数。准备好封面和标题字符串,这些能为视图提供数据源。随后,封面数将被传给初始化程序。
3)等待。等待LoadView方法将Cover Flow设置为主视图,然后开始当前的运行循环(run loop)。
4)提供委托和数据源方法。确保视图控制器能处理一些必要的Cover Flow委托和数据源回调。以下部分将详细介绍这些必要的和可选的方法。
当你完成上述这些目标后,应该会很快出现并运行有效的Cover Flow演示界面。图11-1显示通过视图控制器在代码清单11-3中建立的Cover Flow界面。在该Cover Flow中,蜡笔的不同颜色以一连串圆形样板的形式展现给用户。轻击翻转样板,将显示代表该颜色的6个字符的十六进制代码。

11.3.1 Cover Flow数据源方法
对于标准的Cover Flow操作,视图控制器为coverFlow:requestImageAtIndex:quality方法提供了UIImage。利用所提供的索引确定要返回的图像。此方法对于数据源的正常工作是非常必要的。为了更快地载入图像,可以使用松散的图像生成方式,而不要使用以下代码清单中的数组方式来创建运行中需要的图像。你可以将这些图像存储到稀疏目录下,而只为那些将要使用的图像构建Cover Flow数据源方法。
翻转图层是可选的。用户轻击它们时,通过图层就能集中封面进行浏览。使用翻转图层时,向视图控制器中添加coverFlow:requestFlipLayerAtIndex:方法。此方法返回图像图层以显示翻转项目的后退路径。

11.3.2 Cover Flow委托方法
如代码清单11-3所示,用户选取新页面时,Cover Flow视图产生selectionDidChange:回调方法。使用此方法能更新显示的标签文本,并跟踪最近所选项目的路径。
另一种委托方法是coverFlowFlipDidEnd:,它能通知你翻转动画何时完成。调用这种方法能实现从前向后翻转或者从后向前翻转,因此跟踪了对应状态的路径。请注意翻转视图是显示的还是隐藏的。

代码清单11-3 在视图控制器中构建Cover Flow视图
#import <UIKit/UIKit.h>
#import "CoverFlowView.h"

@interface CoverViewController:UIViewController
{
 CoverFlowView *cfView;
 UICoverFlowLayer *cfLayer;
 UILabel *label;
 NSMutableArray *covers;
 NSMutableArray *titles;
 int whichItem;
 id target;
 SEL selector;
 
 NSMutableDictionary *colorDict;
 UILabel *flippedView;
 BOOL flipOut;
}
@end

//Cover Flow View Controller

@implementation CoverViewController
- (CoverViewController *)init
{
 if (!(self=[super init])) return self;
 //Read in the crayons and set up the arrays and dictionaries
 NSArray *crayons=[[NSString stringWithContentsOfFile:[[NSBundle mainBundle] pathForResource:@"crayons" ofType:@"txt"]] componentsSeparatedByString:@"\n"];
 covers=[[NSMutableArray alloc] init];
 titles=[[NSMutableArray alloc] init];
 colorDict=[[NSMutableDictionary alloc] init];

 //Create the title and cover arrays
 for (NSString *crayon in crayons)
 {
  NSArray *theCrayon=[crayon componentsSeparatedByString:@"#"];
  if ([theCrayon count] !=2) continue;
  [titles addObject:[theCrayon objectAtIndex:0]];
  [covers addObject:createImage([theCrayon objectAtIndex:1])];
  [colorDict setObject:[theCrayon objectAtIndex:1] forKey:[theCrayon objectAtIndex:0]];
 }

 //Create the flip object
 CGRect fliprect=CGRectMake(0.0f,0.0f,480.0f,480.0f);
 flippedView=[[FlipView alloc] initWithFrame:fliprect];
 [flippedView setTransform:CGAffineTransformMakeRotation(3.141592f/2.0f)];
 [flippedView setUserInteractionEnabled:YES];

 //Initialize
 cfView=[[CoverFlowView alloc] initWithFrame:[[UIScreen mainScreen] applicationFrame] andCount:[titles count]];
 [cfView setUserInteractionEnabled:YES];
 [cfView setHost:self];
 cfLayer=[cfView cfLayer];
 label=[cfView label];

 //Finish setting up the Cover Flow Layer
 whichItem=[titles count]/2;
 [cfLayer selectCoverAtIndex:whichItem];
 [cfLayer setDelegate:self];

 selector=NULL;
 target=NULL;

 return self;
}

//Cover Flow delegate methods
- (void)coverFlow:(id)coverFlow selectionDidChange:(int)index
{
 whichItem=index;
 [label setText:[titles objectAtIndex:index]];
}

//Detect the end of the flip - both on reveal and hide
- (void)coverFlowFlipDidEnd:(UICoverFlowLayer *)coverFlow
{
 if(flipOut)
   [[[UIApplication sharedApplication] keyWindow] addSubview:flippedView];
 else
   [flippedView removeFromSuperview];
}

//Cover Flow datasource methods
- (void)coverFlow:(id)coverFlow requestImageAtIndex:(int)index quality:(int)quality
{
 UIImage *whichImg=[covers objectAtIndex:index];
 [coverFlow setImage:[whichImg CGImage] atIndex:index type:quality];
}

//Return a flip layer,one that preferably integrates into the flip presentation
- (id)coverFlow:(UICoverFlowLayer *)coverFlow requestFlipLayerAtIndex:(int)index
{
 if (flipOut) [flippedView removeFromSuperview];
 flipOut=!flipOut;

 //Prepare the flip text
 [flippedView setText:[NSString stringWithFormat:@"%@\n%@",[titles objectAtIndex:index],[colorDict objectForKey:[titles objectAtIndex:index]]]];
 //Flip with a simple blank square
 UIView *view=[[UIView alloc] initWithFrame:CGRectMake(0.0f,0.0f,140.0f,140.0f)];
 [view setBackgroundColor:[UIColor clearColor]];

 return [view layer];
}

//Utility methods
- (CoverFlowView *)cfView {return cfView;}
- (UICoverFlowLayer *)cfLayer {return cfLayer;}
- (int)selectedItem { return whichItem;}

- (void)start
{
 [cfView startHeartbeat:@selector(tick) inRunLoopMode:(id)kCFRunLoopDefaultMode];
 [cfLayer transitionIn:1.0f];
}

- (void)stop
{
 [cfView stopHeartbeat:@selector(tick)];
}

- (void)loadView
{
 [super loadView];
 self.view=cfView;
 [self start];
}

//Callback method for double tap
- (void) doubleTapCallback
{
}
@end

11.4 小结
通过阅读本章可以看出,iPhone编程中一些非常精致的细节都包含在公共的iPhone框架中,而不在正式的SDK中。苹果公司这种非正式策略的意图很明显:你可以在程序中使用这些项目,但是这样做存在一定的风险。在每个固件版本中,你的代码都可能会中断。这就意味着你需要在风险和回报之间寻找最佳的平衡点。
0 0
原创粉丝点击