技术开发 频道

开发者必读iPhone SDK开发基础系列教程

  【IT168技术】总的来说iPhone程序有两类框架,一类是游戏框架,另一类是非游戏框架,这里介绍的是非游戏框架,即基于iPhone 用户界面标准控件的程序框架。

  典型的iPhone程序包含一个Window和几个UIViewController,每个UIViewController管理多个UIView(可能是UITableView、UIWebView、UIImageView等),如图3-24所示。这些UIView之间如何进行层次迭放、显示、隐藏、旋转、移动等都由UIViewController进行管理,而UIViewController之间的切换,通常情况是通过UINavigationController、UITabBarController或UISplitViewController进行切换。接下来笔者会逐一介绍如何使用这三种Controller来切换你的UIViewController,以及在UIViewController中如何组织和管理你的各种UIView。

iPhone程序框架
▲图3-24 iPhone程序框架示意图

iPhone SDK开发基础之自定义仪表控件
▲图书

  iPhone SDK开发基础之OpenFlow编程

  当用户界面需要按页面显示图片时,使用OpenFlow库提供的功能,将要显示的用户界面图片分页进行显示会使编程工作变得非常快捷。该库提供了与OS X桌面Finder程序相同的视觉效果,如图3-46所示就是一个使用OpenFlow库逐页进行图片显示的程序,用户按下屏幕即可进行左右滚动显示,双击图片即可对当前显示的图片进行选取操作。

iPhone SDK开发基础之OpenFlow编程
▲图3-46 OpenFlow编程实例界面

  程序在视图控制器的viewDidAppear()中使用refreshCoverFlow()函数初始化OpenFlow库,通过setNumberOfImages()函数设置图片数量,代码如下。

//  RootViewController.m
- (void)refreshCoverFlow{
        
    CGRect bounds
= [[UIScreen mainScreen] bounds];
    AFOpenFlowView
*coverFlowView = (AFOpenFlowView*)[self.view viewWithTag:kTagCoverflow];
    
if(coverFlowView != nil)
       [coverFlowView removeFromSuperview];    
    coverFlowView
= [[AFOpenFlowView alloc] initWithFrame:CGRectMake(0, -30, bounds.size.width, COVERFLOWHEIGHT)];
    coverFlowView.dataSource
= self;
    coverFlowView.viewDelegate
= self;
    coverFlowView.defaultImage
= [self defaultImage];
    coverFlowView.tag
= kTagCoverflow;
    [self.view addSubview:coverFlowView];

    NSInteger count
= [self numberOfAnimals];
    [coverFlowView setNumberOfImages:count];
    
//...
    
    [coverFlowView release];
    
}

  并在loadView()中初始化图片,将图片从资源中加载并保存在一个NSMutableArray类型的变量imageArray中,代码如下。

- (BOOL)doAddAnimal:(NSString *)name Image:(NSString *)imageName{
    
    UIImage
*image = [UIImage imageNamed: imageName];
    
if(image == nil) return FALSE;
    CGSize size  
= CGSizeMake(179, 208);
    [imageArray addObject:[self resizeImage:image scaledToSize:size]];
    return
TRUE;    
}

  在OpenFlow库的requestImageForIndex delegate方法中直接通过NSMutableArray的索引作为OpenFlow库的图片索引,并通过该索引设置和获取具体图片,代码如下。

//  PageViewController.m
- (void)openFlowView:(AFOpenFlowView *)openFlowView requestImageForIndex: (int)index{
     UIImage
*image =  [imageArray objectAtIndex:index];
     [openFlowView setImage:image forIndex:index];

}

  笔者在OpenFlow库AFOpenFlowView.m文件的touchesEnded()函数中增加了双击回调接口,以便在用户双击图片时通知库的调用者,代码如下。

//AFOpenFlowView.m
- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event {
    
if(((UITouch *)[touches anyObject]).tapCount == 2){
        
if ([self.viewDelegate respondsToSelector:@selector(openFlowView: coverViewDoubleClick:)])
            [self.viewDelegate openFlowView:self coverViewDoubleClick: selectedCoverView.number];
    }    
    [super touchesEnded:touches withEvent:event];    
}

  库的调用者RootViewController类通过接口函数coverViewDoubleClick()即可处理用户双击事件,代码如下。

- (void)openFlowView:(AFOpenFlowView *)openFlowView coverViewDoubleClick:(int)index{
     NSLog(@
"coverViewDoubleClick called!");
     [self showPaintingViewController];
}

  iPhone SDK开发基础之UIPageControl编程

  当用户界面需要按页面进行显示时,使用iOS提供的UIPageControl控件将要显示的用户界面内容分页进行显示会使编程工作变得非常快捷,如图3-47所示就是一个使用UIPageControl控件逐页进行图片显示的程序,用户按下屏幕即可进行左右滚动显示,在屏幕的正上方使用白色的点显示当前滚动到的页面位置。

UIPageControl编程
▲图3-47 UIPageControl编程实例界面

  程序自定义一个SwipeView类,该类通过子类化UIView类并重载其touchesMoved()方法捕获用户滚动的方向,类的定义如下。

//  SwipeView.h
#import
<UIKit/UIKit.h>
#import
<QuartzCore/QuartzCore.h>

@interface SwipeView : UIView {
    CGPoint startTouchPosition;
    NSString
*dirString;
    UIViewController
*host;
}

- (void) setHost: (UIViewController *) aHost;

@
end


//  SwipeView.m
#import
"SwipeView.h"

@implementation SwipeView

- (id)initWithFrame:(CGRect)frame {
    
if ((self = [super initWithFrame:frame])) {
        
// Initialization code
    }
    return self;
}


- (void) setHost: (UIViewController *) aHost
{
    host
= aHost;
}

- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
    UITouch
*touch = [touches anyObject];
    startTouchPosition
= [touch locationInView:self];
    dirString
= NULL;
}

- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event {
    UITouch
*touch = touches.anyObject;
    CGPoint currentTouchPosition
= [touch locationInView:self];
    
#define HORIZ_SWIPE_DRAG_MIN
12
#define VERT_SWIPE_DRAG_MAX
4
    
    
if (fabsf(startTouchPosition.x - currentTouchPosition.x) >=
        HORIZ_SWIPE_DRAG_MIN
&&
        fabsf(startTouchPosition.y
- currentTouchPosition.y) <=
        VERT_SWIPE_DRAG_MAX)     {
        
// Horizontal Swipe
        
if (startTouchPosition.x < currentTouchPosition.x) {
            dirString
= kCATransitionFromLeft;
        }
        
else
            dirString
= kCATransitionFromRight;
    }
}

- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event {
    
if (dirString) [host swipeTo:dirString];
}

@
end

  在捕获用户滚动的方向后,SwipeView类通过用户设置的host成员变量回调其swipeTo()方法,host成员变量在类中定义为UIViewController,在编译时编译器会产生警告,这里不用管它,只需要SwipeView类的使用者设置host成员变量并实现swipeTo()方法即可。

  SwipeView类的使用者为PageViewController类,该类实现程序的主界面,在这个自定义的UIViewController类中实现swipeTo()方法,代码如下。

//  PageViewController.m
- (void) swipeTo: (NSString *) aDirection{
    UIPageControl
*pageControl = [[[contentView superview] subviews] lastObject];
    
    
if ([aDirection isEqualToString:kCATransitionFromRight])
    {
        
if (currentPage == 5) return;
        [pageControl setCurrentPage:currentPage
+ 1];
    }
else {
        
if (currentPage == 0) return;
        [pageControl setCurrentPage:currentPage
- 1];
    }
    
    [self pageTurn:pageControl];
}

  在该回调方法中根据用户滚动的方向来设置UIPageControl的currentPage属性,如果是向右方滚动则页面计数加一,如果用户滚动的方向是向左,则页面计数减一。设置UIPageControl的currentPage属性以后,PageViewController对象再调用其pageTurn()方法交换页面显示内容,并将图片显示出来,代码如下。

- (void) pageTurn: (UIPageControl *) pageControl{
    CATransition
*transition;
    
int secondPage = [pageControl currentPage];
    
if ((secondPage - currentPage) > 0)
        transition
= [self getAnimation:@"fromRight"];
    
else
        transition
= [self getAnimation:@"fromLeft"];
    
    UIImageView
*newView = (UIImageView *)[[contentView subviews] objectAtIndex:0];
    [newView setImage:[UIImage imageNamed:[NSString stringWithFormat:@
"ipad_ wallpaper%02d.jpg", secondPage + 1]]];
    [contentView exchangeSubviewAtIndex:
0 withSubviewAtIndex:1];
    [[contentView layer] addAnimation:transition forKey:@
"transitionView Animation"];
    
    currentPage
= [pageControl currentPage];
}

  在主pageTurn()方法实现中,PageViewController类通过UIView的exchangeSubview AtIndex()方法实现页面内容的切换。

  本节相关的完整Xcode工程源代码文件请参考本书附带的光盘中的PageControl工程。

  iPhone SDK开发基础之使用UINavigationController组织和管理UIView

  当你的程序具有层次化的工作流时,就比较适合使用UINavigationController来管理UIViewController,即用户可以从上一层界面进入下一层界面,在下一层界面处理完以后又可以简单地返回到上一层界面,UINavigationController使用堆栈的方式来管理UIViewController,进入下一层界面的代码如下。


▲图3-25 UINavigationController

  程序框架实例界面

  [self.navigationController pushViewController:nextController animated:YES];

  返回上一层界面的代码如下。

  [self.navigationController popViewControllerAnimated:YES];

  如图3-25所示,屏幕左上方的“Animal List”按钮是返回按钮,注意这个返回按钮是UINavigationController自动添加的,不需要编写任何代码在界面上添加按钮或者实现按钮操作,当程序使用pushViewController()函数将ViewController添加进UINavigation Controller的时候,UINavigationController就自动显示这个返回按钮,用户单击这个“Animal List”按钮就可以回到原先的界面,UINavigationController的这种运行机制产生这样的效果,用户可以一层一层地进入更深的界面层次,然后又可以一层一层的按顺序返回,使用这样的方式来组织用户界面非常方便。

  本节相关的完整Xcode工程源代码文件请参考本书附带的光盘中的Zoo实例。本文节选自《iOS软件开发揭密:iPhone&iPad企业应用和游戏开发》一书。《iOS软件开发揭密:iPhone&iPad企业应用和游戏开发》一书已由电子工业出版社正式出版,本书由虞斌著。

0
相关文章