《iPhone与iPad开发实战—iOS经典应用剖析》连载五

简介: RootViewController<span style="font-family:宋体">的</span>h<span style="font-family:宋体">文件编写完成我们接着编写</span>RootViewController<span style="font-family:宋体">的</span>m<span style="font-family:宋体">文件如“代码清
RootViewController h 文件编写完成我们接着编写RootViewController m 文件如“代码清单3-2 Password/Classes/RootViewController.m ”所示。
【代码清单3-1】 Password/Classes/RootViewController.m
#import "RootViewController.h"
#import "MainViewController.h"
#import "FlipsideViewController.h"


@implementation RootViewController

@synthesize infoButton;
@synthesize flipsideNavigationBar;
@synthesize mainViewController;
@synthesize flipsideViewController;


- (void)viewDidLoad {

MainViewController*viewController = [[MainViewController alloc]initWithNibName:@"MainView" bundle:nil];
self.mainViewController= viewController;
[viewControllerrelease];

[self.viewinsertSubview:mainViewController.view belowSubview:infoButton];
}


- (void)loadFlipsideViewController {

FlipsideViewController*viewController = [[FlipsideViewController alloc]initWithNibName:@"FlipsideView" bundle:nil];
self.flipsideViewController= viewController;
[viewControllerrelease];

//Set up the navigation bar
UINavigationBar*aNavigationBar = [[UINavigationBar alloc] initWithFrame:CGRectMake(0.0, 0.0,320.0, 44.0)];
aNavigationBar.barStyle= UIBarStyleBlackOpaque;
self.flipsideNavigationBar= aNavigationBar;
[aNavigationBarrelease];

UIBarButtonItem*buttonItem = [[UIBarButtonItem alloc]
initWithBarButtonSystemItem:UIBarButtonSystemItemDone
target:selfaction:@selector(toggleView)];
UINavigationItem*navigationItem = [[UINavigationItem alloc] initWithTitle:@"PasswordGenerator"];
navigationItem.rightBarButtonItem= buttonItem;
[flipsideNavigationBarpushNavigationItem:navigationItem animated:NO];
[navigationItemrelease];
[buttonItemrelease];
}


- (IBAction)toggleView {
/*
  This method is called when the info or Donebutton is pressed.
  It flips the displayed view from the main viewto the flipside view and vice-versa.
  */
if(flipsideViewController == nil) {
[selfloadFlipsideViewController];
}

UIView*mainView = mainViewController.view;
UIView*flipsideView = flipsideViewController.view;

[UIViewbeginAnimations:nil context:NULL];
[UIViewsetAnimationDuration:1];
[UIViewsetAnimationTransition:([mainView superview]
?UIViewAnimationTransitionFlipFromRight
  : UIViewAnimationTransitionFlipFromLeft)forView:self.view cache:YES];

if([mainView superview] != nil) {
[flipsideViewControllerviewWillAppear:YES];
[mainViewControllerviewWillDisappear:YES];
[mainViewremoveFromSuperview];
[infoButton removeFromSuperview];
[self.viewaddSubview:flipsideView];
[self.viewinsertSubview:flipsideNavigationBar aboveSubview:flipsideView];
[mainViewControllerviewDidDisappear:YES];
[flipsideViewControllerviewDidAppear:YES];

}else {
[mainViewControllerviewWillAppear:YES];
[flipsideViewControllerviewWillDisappear:YES];
[flipsideViewremoveFromSuperview];
[flipsideNavigationBarremoveFromSuperview];
[self.viewaddSubview:mainView];
[self.viewinsertSubview:infoButton aboveSubview:mainViewController.view];
[flipsideViewControllerviewDidDisappear:YES];
[mainViewControllerviewDidAppear:YES];
}
[UIViewcommitAnimations];
}



-(BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation{
//Return YES for supported orientations
return(interfaceOrientation == UIInterfaceOrientationPortrait);
}


- (void)didReceiveMemoryWarning {
[superdidReceiveMemoryWarning]; // Releases the view if it doesn't have a superview
//Release anything that's not essential, such as cached data
}


- (void)dealloc {
[infoButtonrelease];
[flipsideNavigationBarrelease];
[mainViewControllerrelease];
[flipsideViewControllerrelease];
[superdealloc];
}


@end



m 文件中方法很多,值得我们关注有3 个:viewDidLoad loadFlipsideViewController toggleView ,下分别介绍这个3 个方法。
viewDidLoad 是视图加载完成还没有显示时候回调的方法,在本应用中该方法是创建一个主视图控制器,下面语句就是从一个给定nib 文件名字创建一个控制器的通用方法:
MainViewController *viewController =[[MainViewController alloc] initWithNibName:@"MainView" bundle:nil];
主视图控制器创建完成需要把指针赋值给本类的mainViewController 属性,因为该属性设置retain ,这样可以防止内存泄漏,接着再释放刚才创建的viewController 对象。
self.mainViewController= viewController;
[viewControllerrelease];
viewDidLoad 该方法最后,通过下面的语句实现,将创建的主视图控制器中的视图放入到当前视图中作为子视图,并且位于 按钮下面,在iOS 中视图可以有子视图,子视图摆放是有顺序的,前后顺序的不同会引起遮挡和影响事件响应。
[self.view insertSubview:mainViewController.viewbelowSubview:infoButton];
– insertSubview:aboveSubview: 类似的方法还有:
· –addSubview: ,直接在前面增加子视图;
· –insertSubview:atIndex: ,按照索引插入子视图;
· –exchangeSubviewAtIndex:withSubviewAtIndex: ,交换两个子视图的顺序,常用于视图切换。
loadFlipsideViewController 方法主要作用就是创建背后视图和上面的导航栏,创建背后视图控制器方法与主视图控制器方法一样,这里不再多说了。在iOS 中导航栏比较麻烦的控件,它涉及到导航栏(Navigation Bar )、导航项目(Navigation Item )和导航按钮(Bar Button Item ),在导航栏中包含导航项目,导航项目包含导航按钮,导航项目可以有标题,导航按钮可以有左右两个按钮,它们的关系如图3-35 所示。



3-35 导航栏、导航项目和导航按钮的关系
因此我们需要创建这3 个对象,首先创建导航栏使用下面的语句:
UINavigationBar *aNavigationBar = [[UINavigationBaralloc] initWithFrame:CGRectMake(0.0, 0.0, 320.0, 44.0)];
使用该方法可以通过指定一个矩形轮廓来创建一个导航栏,创建完成导航栏后还要指定它的样式:
aNavigationBar.barStyle= UIBarStyleBlackOpaque;
创建完成导航栏接着创建导航按钮,然后再创建导航项目,再把导航按钮放到导航项目中。下面语句是创建一个导航按钮:
UIBarButtonItem *buttonItem = [[UIBarButtonItemalloc]
initWithBarButtonSystemItem:UIBarButtonSystemItemDone
target:selfaction:@selector(toggleView)];
在该语句中指定了按钮的样式,同时指定了按钮点击事件触发的时候调用的方法toggleView 。导航项目创建是通过下面语句实现的:
UINavigationItem *navigationItem =[[UINavigationItem alloc] initWithTitle:@"Password Generator"];
在该语句中通过指定标题来构造一个导航项目,然后再通过下面的语句把刚才创建的导航按钮放在到导航项目中,作为它的右按钮。
navigationItem.rightBarButtonItem = buttonItem;
最后还要把导航项目放入到导航栏中,这个目标是通过下面语句实现的,并且要求动画显示:
[flipsideNavigationBar pushNavigationItem:navigationItemanimated:NO];
导航栏维护一个堆栈,通过发出pushNavigationItem:animated: 消息把一个导航项目压栈,发出popNavigationItemAnimated: 消息把一个导航项目出栈,当前视图显示的是栈顶的导航项目,所以,压栈可以进入下一级导航项目,而出栈可以返回以上一级导航项目。
toggleView 方法是点击主视图的 按钮和背后视图的Done 按钮时候触发的方法,在该方法中实现了两个视图的切换。在该方法中主要涉及到两个知识点,一个是UIView 切换问题,另一个是UIView 动画问题。两个问题是相伴而生的,在UIView 切换的时候往往伴随着动画发生。下面我们先看看UIView 切换问题。
在视图切换有很多种方式,可以采用模态视图控制器切换、导航控制器切换和普通 视图控制器切换。在本应用中采用的是普通视图控制器却换,它是定义一个根控制器,通过根控制器来控制其它视图交替切换。RootViewController 就是视图控制器,其中有自己的View 对象(根视图),当主视图加载时候,将主视图作为根视图的子视图放入,当主视图向背后面翻转的时候,把主视图从根视图中移除掉,把背后视图作为根视图的子视图放入。当背后面向主视图翻转的时候,把背后视图从根视图中移除掉,把主视图作为根视图的子视图放入,这样反反复复。
采用模态视图控制器可以参考苹果官方文档http://developer.apple.com/library/ios/#featuredarticles/ViewControllerPGforiPhoneOS/ModalViewControllers/ModalViewControllers.html

下面我们看看toggleView 方法的代码,该方法首先执行下面的语句,实现初始化背后视图控制器目的,这里有一个判断如果flipsideViewController nil 时候才去发出loadFlipsideViewController 消息,可以防止多重加载。
if(flipsideViewController == nil) {
   [selfloadFlipsideViewController];
}
接下来通过下面语句从视图控制器其中获得主视图和背后视图,由于在viewDidLoad 方法中创建了主视图控制器,在loadFlipsideViewController 方法中创建了背后视图控制器,因此在这里获得的视图对象不会是nil 的。
UIView*mainView = mainViewController.view;
UIView*flipsideView = flipsideViewController.view;
iOS 中动画有多种形式,这里的视图翻转是属于UIView 级别动画,UIView 级别动画必须从[UIView beginAnimations:nilcontext:NULL] 开始到[UIViewcommitAnimations] 结束。在本应用中与UIView 级别动画有关代码如下:
[UIViewbeginAnimations:nil context:NULL];
[UIViewsetAnimationDuration:1];
[UIViewsetAnimationTransition:([mainView superview]
?UIViewAnimationTransitionFlipFromRight
  : UIViewAnimationTransitionFlipFromLeft)forView:self.view cache:YES];
… …
[UIViewcommitAnimations];
setAnimationDuration: 语句设置动画持续时间,setAnimationTransition:forView: cache: 方法中第一个参数定义动画转变类型,第二个参数是当前视图对象,第三个参数是是否使用缓冲区。动画转变类型是指动画样式,其取值是UIViewAnimationTransition 枚举类型,UIViewAnimationTransition 的成员有:
· UIViewAnimationTransitionNone ,不指定过渡类型;
· UIViewAnimationTransitionFlipFromLeft ,指定从左侧翻转;
· UIViewAnimationTransitionFlipFromRight ,指定从右侧翻转;
· UIViewAnimationTransitionCurlUp ,指定向上卷起;
· UIViewAnimationTransitionCurlDown ,指定向下卷起。
虽然,在本应用中没有使用,但是UIView 级别动画中还有一个重要方法setAnimationCurve: ,该方法可以设置动画曲线,动画曲线是决定动画进入和退出屏幕的方式。其它取值是UIViewAnimationCurve 枚举类型,UIViewAnimationCurve 的成员有:
· UIViewAnimationCurveEaseInOut ,淡入淡出,开始时候慢,慢变快,中间最快,然后变慢;
· UIViewAnimationCurveEaseIn ,淡入,开始时候慢然后越来越快;
· UIViewAnimationCurveEaseOut ,淡出,开始快然后越来越慢;
· UIViewAnimationCurveLinear ,线性匀速,开始和结束是一个速度。
判断语句if ([mainView superview] != nil) {} 可以判断当前的视图是否为主视图,因为只有当前视图是主视图情况下主视图才有父视图,否则就是当前视图就是背后视图。如果当前视图是主视图时候代码如下:
[flipsideViewControllerviewWillAppear:YES];
[mainViewControllerviewWillDisappear:YES];
[mainViewremoveFromSuperview];
[infoButton removeFromSuperview];
[self.viewaddSubview:flipsideView];
[self.viewinsertSubview:flipsideNavigationBar aboveSubview:flipsideView];
[mainViewControllerviewDidDisappear:YES];
[flipsideViewControllerviewDidAppear:YES];
上面的这段代码就是要实现从主视图向背后面翻转,因此,需要在根视图中移除主视图[mainView removeFromSuperview] ,同时还移除了infoButton 对象[infoButton removeFromSuperview] ,它们两个都是在主视图上显示的。 [self.viewaddSubview:flipsideView] 方法把背后视图添加到当前视图。在通过 [self.viewinsertSubview:flipsideNavigationBar aboveSubview:flipsideView] 语句把导航栏添加到背后视图上面,使得导航栏与背后视图同是当前视图的子视图,只不过是导航栏在前面。
此外,代码中还用到了控制器中视图出现和消失的几个事件方法:
· viewWillAppear: ,通知视图控制器,它的视图将要可见;
· viewWillDisappear: ,通知视图控制器,它的视图将要消失;
· viewDidDisappear: ,通知视图控制器,它的视图已经消失;
· viewDidAppear: ,通知视图控制器,它的视图已经可见。
事实上,这几个方法经常在视图控制器中被重写,用于处理视图的不同生命周期中会触发的事件,它们与viewDidLoad viewDidUnload 事件类似,它们调用会更加频繁触发。其中viewDidLoad viewWillAppear: 很类似,viewDidLoad 是视图被创建时候触发,接着视图变成可见的时候会触发 viewWillAppear: 事件,当视图变换到别的视图,视图从可见变成不可见,再次回来时候,视图从不可见变成可见viewDidLoad 方法就不会触发 ,而 viewWillAppear: 事件会触发。
目录
相关文章
|
1月前
|
开发框架 前端开发 Android开发
Flutter 与原生模块(Android 和 iOS)之间的通信机制,包括方法调用、事件传递等,分析了通信的必要性、主要方式、数据传递、性能优化及错误处理,并通过实际案例展示了其应用效果,展望了未来的发展趋势
本文深入探讨了 Flutter 与原生模块(Android 和 iOS)之间的通信机制,包括方法调用、事件传递等,分析了通信的必要性、主要方式、数据传递、性能优化及错误处理,并通过实际案例展示了其应用效果,展望了未来的发展趋势。这对于实现高效的跨平台移动应用开发具有重要指导意义。
157 4
|
1月前
|
编解码 测试技术 开发工具
测试 iPhone 应用在不同屏幕尺寸和分辨率下的响应式效果
【10月更文挑战第23天】测试 iPhone 应用在不同屏幕尺寸和分辨率下的响应式效果是确保应用质量和用户体验的重要环节。通过手动测试、自动化测试、视觉效果评估、性能测试、用户体验测试等多种方法的综合运用,能够全面地发现应用在响应式效果方面存在的问题,并及时进行解决和优化。同时,持续的测试和优化也是不断提升应用质量和用户满意度的关键。
|
2月前
|
设计模式 安全 Swift
探索iOS开发:打造你的第一个天气应用
【9月更文挑战第36天】在这篇文章中,我们将一起踏上iOS开发的旅程,从零开始构建一个简单的天气应用。文章将通过通俗易懂的语言,引导你理解iOS开发的基本概念,掌握Swift语言的核心语法,并逐步实现一个具有实际功能的天气应用。我们将遵循“学中做,做中学”的原则,让理论知识和实践操作紧密结合,确保学习过程既高效又有趣。无论你是编程新手还是希望拓展技能的开发者,这篇文章都将为你打开一扇通往iOS开发世界的大门。
|
2月前
|
搜索推荐 IDE API
打造个性化天气应用:iOS开发之旅
【9月更文挑战第35天】在这篇文章中,我们将一起踏上iOS开发的旅程,通过创建一个个性化的天气应用来探索Swift编程语言的魅力和iOS平台的强大功能。无论你是编程新手还是希望扩展你的技能集,这个项目都将为你提供实战经验,帮助你理解从构思到实现一个应用的全过程。让我们开始吧,构建你自己的天气应用,探索更多可能!
77 1
|
4月前
|
搜索推荐 API 开发工具
打造个性化天气应用:从零开始的iOS开发之旅
【8月更文挑战第31天】本文是一篇针对初学者的iOS应用开发指南,将引导读者通过Swift和iOS SDK构建一个简单而美观的天气应用。我们将探索如何利用API获取实时天气数据,并在应用中实现用户友好的界面设计。文章不仅包括代码示例,还提供了设计理念和用户体验优化的建议,旨在帮助初学者理解iOS开发的基础知识,并激发他们创造个性化应用的兴趣。
|
1月前
|
安全 Swift iOS开发
Swift 与 UIKit 在 iOS 应用界面开发中的关键技术和实践方法
本文深入探讨了 Swift 与 UIKit 在 iOS 应用界面开发中的关键技术和实践方法。Swift 以其简洁、高效和类型安全的特点,结合 UIKit 丰富的组件和功能,为开发者提供了强大的工具。文章从 Swift 的语法优势、类型安全、编程模型以及与 UIKit 的集成,到 UIKit 的主要组件和功能,再到构建界面的实践技巧和实际案例分析,全面介绍了如何利用这些技术创建高质量的用户界面。
33 2
|
1月前
|
JSON 前端开发 API
探索iOS开发之旅:打造你的第一个天气应用
【10月更文挑战第36天】在这篇文章中,我们将踏上一段激动人心的旅程,一起构建属于我们自己的iOS天气应用。通过这个实战项目,你将学习到如何从零开始搭建一个iOS应用,掌握基本的用户界面设计、网络请求处理以及数据解析等核心技能。无论你是编程新手还是希望扩展你的iOS开发技能,这个项目都将为你提供宝贵的实践经验。准备好了吗?让我们开始吧!
|
1月前
|
Swift iOS开发 UED
如何使用Swift和UIKit在iOS应用中实现自定义按钮动画
本文通过一个具体案例,介绍如何使用Swift和UIKit在iOS应用中实现自定义按钮动画。当用户点击按钮时,按钮将从圆形变为椭圆形,颜色从蓝色渐变到绿色;释放按钮时,动画以相反方式恢复。通过UIView的动画方法和弹簧动画效果,实现平滑自然的过渡。
59 1
|
1月前
|
编解码 iOS开发 UED
响应式设计在 iPhone 开发适配中的具体应用
【10月更文挑战第23天】响应式设计在 iPhone 开发适配中扮演着至关重要的角色,它能够帮助我们打造出适应不同屏幕尺寸和用户需求的高质量应用。通过合理运用响应式设计的原则和方法,我们可以在提供良好用户体验的同时,提高开发效率和应用的可维护性。
|
2月前
|
Swift iOS开发 UED
如何使用Swift和UIKit在iOS应用中实现自定义按钮动画
【10月更文挑战第18天】本文通过一个具体案例,介绍如何使用Swift和UIKit在iOS应用中实现自定义按钮动画。当用户按下按钮时,按钮将从圆形变为椭圆形并从蓝色渐变为绿色;释放按钮时,动画恢复原状。通过UIView的动画方法和弹簧动画效果,实现平滑自然的动画过渡。
62 5