UIScreen
对象来取得,具体代码如下所示:
UIWindow* aWindow = [[[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]] autorelease]; |
frame
、bounds
、和center
属性声明来跟踪自己的大小和位置。frame
属性包含一个矩形,即边框矩形,用于指定视图相对于其父视图坐标系统的位置和大小。bounds
属性也包含一个矩形,即边界矩形,负责定义视图相对于本地坐标系统的位置和大小。虽然边界矩形的原点通常被设置为 (0, 0),但这并不是必须的。center
属性包含边框矩形的中心点。
边框矩形frame是一个通过bounds
和center
属性计算得到的便利值
。
但是设置其中的一个属性会引起其它属性的改变,具体关系如下:
当您设置frame
属性时,bounds
属性的大小会被设置为与frame
属性的大小相匹配的值,center
属性也会被调整为与新的边框中心点相匹配的值。
当您设置center
属性时,frame
的原点也会随之改变。
bounds
矩形的大小时,frame
矩形的大小也会随之改变。
autoresizesSubviews
属性声明被设置为YES
,则其子视图会根据autoresizingMask
属性的值自动进行尺寸调整。
自动尺寸调整掩码 |
描述 |
---|---|
|
这个常量如果被设置,视图将不进行自动尺寸调整。 |
|
这个常量如果被设置,视图的高度将和父视图的高度一起成比例变化。否则,视图的高度将保持不变。 |
|
这个常量如果被设置,视图的宽度将和父视图的宽度一起成比例变化。否则,视图的宽度将保持不变。 |
|
这个常量如果被设置,视图的左边界将随着父视图宽度的变化而按比例进行调整。否则,视图和其父视图的左边界的相对位置将保持不变。 |
|
这个常量如果被设置,视图的右边界将随着父视图宽度的变化而按比例进行调整。否则,视图和其父视图的右边界的相对位置将保持不变。 |
|
这个常量如果被设置,视图的底边界将随着父视图高度的变化而按比例进行调整。否则,视图和其父视图的底边界的相对位置将保持不变。 |
|
这个常量如果被设置,视图的上边界将随着父视图高度的变化而按比例进行调整。否则,视图和其父视图的上边界的相对位置将保持不变。 |
applicationDidFinishLaunching:
方法和视图控制器的loadView
方法。您可以通过下面的方法来操作视图层次中的视图对象:
调用父视图的addSubview:
方法来添加视图,该方法将一个视图添加到子视图列表的最后。
调用父视图的insertSubview:...
方法可以在父视图的子视图列表中间插入视图。
调用父视图的bringSubviewToFront:
、sendSubviewToBack:
、或exchangeSubviewAtIndex:withSubviewAtIndex:
方法可以对父视图的子视图进行重新排序。使用这些方法比从父视图中移除子视图并再次插入要快一些。
调用子视图(而不是父视图)的removeFromSuperview
方法可以将子视图从父视图中移除。
opaque
属性声明设置为
YES
,以提高描画代码的总体效率。当您将视图标识为不透明时,UIKit会避免对该视图正下方的内容进行描画。这不仅减少了描画开销的时间,而且减少内容合成需要的工作。然而,只有当您能确定视图提供的内容为不透明时,才能将这个属性设置为
YES
;如果您不能保证视图内容总是不透明,则应该将它设置为
NO
。
提高描画性能(特别是在滚动过程)的另一个方法是将视图的clearsContextBeforeDrawing
属性设置为NO
。当这个属性被设置为YES
时,UIKIt会在调用drawRect:
方法之前,把即将被该方法更新的区域填充为透明的黑色。将这个属性设置为NO
可以取消相应的填充操作,而由应用程序负责完全重画传给drawRect:
方法的更新矩形中的部分。这样的优化在滚动过程中通常是一个好的折衷。
UIKit为提供了一些简化事件处理、甚至完全关闭事件流的编程接口。下面对这些方法进行总结:
关闭事件的传递。缺省情况下,视图会接收触摸事件。但是,您可以将其userInteractionEnabled
属性声明设置为NO
,关闭事件传递的功能。隐藏或透明的视图也不能接收事件。
在一定的时间内关闭事件的传递。应用程序可以调用UIApplication
的beginIgnoringInteractionEvents
方法,并在随后调用endIgnoringInteractionEvents
方法来实现这个目的。前一个方法使应用程序完全停止接收触摸事件消息,第二个方法则重启消息的接收。某些时候,当您的代码正在执行动画时,可能希望关闭事件的传递。
打开多点触摸的传递。 缺省情况下,视图只接收多点触摸序列的第一个触摸事件,而忽略所有其它事件。如果您希望视图处理多点触摸,就必须使它启用这个功能。在代码或Interface Builder的查看器窗口中将视图的multipleTouchEnabled
属性设置为YES
,就可以实现这个目标。
将事件传递限制在某个单独的视图上。 缺省情况下,视图的exclusiveTouch
属性被设置为NO
。将这个属性设置为YES
会使相应的视图具有这样的特性:即当该视图正在跟踪触摸动作时,窗口中的其它视图无法同时进行跟踪,它们不能接收到那些触摸事件。然而,一个标识为“独占触摸”的视图不能接收与同一窗口中其它视图相关联的触摸事件。如果一个手指接触到一个独占触摸的视图,则仅当该视图是窗口中唯一一个跟踪手指的视图时,触摸事件才会被传递。如果一个手指接触到一个非独占触摸的视图,则仅当窗口中没有其它独占触摸视图跟踪手指时,该触摸事件才会被传递。
将事件传递限制在子视图上。一个定制的UIView
类可以通过重载hitTest:withEvent:
方法来将多点触摸事件的传递限制在它的子视图上。这个技巧的讨论请参见“事件处理技巧”部分。
跟踪UITouch对象的变化
在事件处理代码中,您可以将触摸状态的相关位置保存下来,以便在必要时和变化之后的UITouch
实例进行比较。作为例子,假定您希望将每个触摸对象的最后位置和其初始位置进行比较,则在touchesBegan:withEvent:
方法中,您可以通过locationInView:
方法得到每个触摸对象的初始位置,并以UITouch
对象的地址作为键,将它们存储在CFDictionaryRef
封装类型中;然后,在touchesEnded:withEvent:
方法中,可以通过传入UITouch
对象的地址取得该对象的初始位置,并将它和当前位置进行比较(您应该使用CFDictionaryRef
类型,而不是NSDictionary
对象,因为后者需要对其存储的项目进行拷贝,而UITouch
类并不采纳NSCopying
协议,该协议在对象拷贝过程中是必须的)。
对子视图或层上的触摸动作进行触碰测试
定制视图可以用UIView
的hitTest:withEvent:
方法或CALayer
的hitTest:
方法来寻找接收触摸事件的子视图或层,进而正确地处理事件。下面的例子用于检测定制视图的层中的“Info” 图像是否被触碰。
- (void)touchesEnded:(NSSet*)touches withEvent:(UIEvent*)event { |
CGPoint location = [[touches anyObject] locationInView:self]; |
CALayer *hitLayer = [[self layer] hitTest:[self convertPoint:location fromView:nil]]; |
if (hitLayer == infoImage) { |
[self displayInfo]; |
} |
} |
如果您有一个携带子视图的定制视图,就需要明确自己是希望在子视图的级别上处理触摸事件,还是在父视图的级别上进行处理。如果子视图没有实现touchesBegan:withEvent:
、touchesEnded:withEvent:
、或者touchesMoved:withEvent:
方法,则这些消息就会沿着响应者链被传播到父视图。然而,由于多次触碰和多点触摸事件与发生这些动作所在的子视图是互相关联的,所以父视图不会接收到这些事件。为了保证能接收到所有的触摸事件,父视图必须重载hitTest:withEvent:
方法,并在其中返回其本身,而不是它的子视图。
确定多点触摸序列中最后一个手指何时离开
当您希望知道一个多点触摸序列中的最后一个手指何时从视图离开时,可以将传入的集合参数中包含的UITouch
对象数量和UIEvent
参数对象中与该视图关联的触摸对象数量相比较。请看下面的例子:
- (void)touchesEnded:(NSSet*)touches withEvent:(UIEvent*)event { |
if ([touches count] == [[event touchesForView:self] count]) { |
// last finger has lifted.... |
} |
} |
motionBegan:withEvent:
消息的方式向第一响应者发送一个运动事件,如果第一响应者不能处理,该事件就在响应者链中传递;如果摆动持续的时间小于1秒左右,系统就会向第一响应者发送motionEnded:withEvent:
消息;但是,如果摆动时间持续更长,如果系统确定当前的动作不是摆动,则第一响应者会收到一个motionCancelled:withEvent:
消息。copy:
或cut:
方法。通常情况下,第一响应者—也就是您的定制视图—会实现这些方法,但如果没有实现的话,该消息会按正常的方式进入响应者链。请注意,UIResponderStandardEditActions
非正式协议声明了这些方法。
在copy:
或cut:
消息的响应代码中,您需要把和选定内容相对应的对象或数据以尽可能多的表示形式写入到粘贴板上。这个操作涉及到如下这些步骤(假定只有一个的粘贴板数据项):
标识或取得和选定内容相对应的对象或二进制数据。
二进制数据必须封装在NSData
对象中。其它可以写入到粘贴板的对象必须是属性列表对象—也就是说,必须是下面这些类的对象:NSString
、NSArray
、NSDictionary
、NSDate
、NSNumber
、或者NSURL
(有关属性列表对象的更多信息,请参见属性列表编程指南)。
可能的话,请为对象或数据生成一或多个其它的表示。
举例来说,在之前提到的为选定图像创建UIImage
对象的步骤中,您可以通过UIImageJPEGRepresentation
或UIImagePNGRepresentation
函数将图像转换为不同的表示。
取得粘贴板对象。
在很多情况下,使用通用粘贴板就可以了。您可以通过generalPasteboard
类方法来取得该对象。
为写入到粘贴板数据项的每个数据表示分配一个合适的UTI。
这个主题的讨论请参见“粘贴板的概念”部分。
将每种表示类型的数据写入到第一个粘贴板数据项中:
向粘贴板对象发送setData:forPasteboardType:
消息可以写入数据对象。
向粘贴板对象发送setValue:forPasteboardType:
消息可以写入属性列表对象。
cut:
方法)命令,需要从应用程序的数据模型中移除选定内容所代表的对象,并更新视图。UIView
对象的区域内。视图定义描画发生的屏幕区域。
重要提示:由于在位图或PDF上下文中进行描画时使用的是左下原点,所以在将描画结果渲染到视图上的时候,必须对坐标系统进行补偿。换句话说,如果您创建一个图像,并调用CGContextDrawImage
函数来进行描画,则该图像在缺省情况下是上下颠倒的。为了纠正这个问题,您必须将CTM的y轴进行翻转(即将该值乘以-1
),使其原点从左下角移动到视图的左上角。
UIImage
对象来包装您所创建的CGImageRef
类型,则不需要修改CTM。UIImage
对象会自动对CGImageRef
类型的坐标系统进行翻转补偿。
Tip |
Action |
---|---|
使描画工作最小化 |
在每个更新周期中,您应该只更新视图中真正发生变化的部分。如果您使用UIView的 |
尽可能将视图标识为不透明 |
合成不透明的视图所需要的开销比合成部分透明的视图要少得多。一个不透明的视图必须不包含任何透明的内容,且视图的 |
删除不透明的PNG文件中的alpha通道 |
如果一个PNG图像的每个像素都是不透明的,则将其alpha通道删除可以避免对包含该图像的图层进行融合操作,从而很大程度上简化了该图像的合成,提高描画的性能。 |
在滚动过程中重用表格单元和视图 |
应该避免在滚动过程种创建新的视图。创建新视图的开销会减少用于更新屏幕的时间,因而导致滚动不平滑。 |
避免在滚动过程中清除原先的内容 |
缺省情况下,在调用 |
在描画过程中尽可能不改变图形状态 |
改变图形状态需要窗口服务器的参与。如果您要描画的内容使用类似的图形状态,则尽可能将这些内容一起描画,以减少需要改变的状态。 |
becomeFirstResponder
方法来为可编辑的文本视图显示键盘。调用这个方法可以使目标视图成为第一响应者,并开始编辑过程,其效果和用户触击该视图是一样的。
resignFirstResponder
方法来取消键盘。当文本视图失去第一响应者的状态时,就会结束其当前的编辑会话,将这个变化通知它的
委托
对象,并取消键盘。
UIScrollView
(或其子类,如UITableView
)对象。当键盘被显示出来时,您需要做的只是调整滚动视图的尺寸,并将目标文本对象滚动到合适的位置。为此,在UIKeyboardDidShowNotification
通告的处理代码中需要进行如下操作:
取得键盘的尺寸。
将滚动视图的高度减去键盘的高度。
将目标文本框滚动到视图中。
用UIScrollView
类的scrollRectToVisible:animated:方法
如果您的用户界面包含UIWebView
对象,就可以显示本地或网络上的内容。对于本地的内容,您可以动态创建,也可以使用文件,然后调用loadData:MIMEType:textEncodingName:baseURL:
或loadHTMLString:baseURL:
方法;如果要从网络加载,则需要创建一个NSURLRequest
对象,然后传递给web视图对象的loadRequest:
方法。
stopLoading
方法。通常情况下,您可以在web视图的视图控制器的
viewWillDisappear:
方法中执行这些代码。如果需要确定一个请求是否处于等待状态,可以通过web视图的
loading
属性来判断。
部分;有关应用程序家目录本身的信息,则请参见 “应用程序沙箱”部分。
目录 |
描述 |
---|---|
<Application_Home> |
这是程序包目录,包含应用程序的本身。由于应用程序必须经过签名,所以您在运行时不能对这个目录中的内容进行修改,否则可能会使应用程序无法启动。 在iPhone OS 2.1及更高版本的系统,iTunes不对这个目录的内容进行备份。但是,iTunes会对在App Store上购买的应用程序进行一次初始的同步。 |
<Application_Home> |
您应该将所有的应用程序数据文件写入到这个目录下。这个目录用于存储用户数据或其它应该定期备份的信息。有关如何取得这个目录路径的信息,请参见“获取应用程序目录的路径”部分。 iTunes会备份这个目录的内容。 |
<Application_Home> |
这个目录包含应用程序的偏好设置文件。您不应该直接创建偏好设置文件,而是应该使用 iTunes会备份这个目录的内容。 |
<Application_Home> |
这个目录用于存放应用程序专用的支持文件,保存应用程序再次启动过程中需要的信息。您的应用程序通常需要负责添加和删除这些文件,但在对设备进行完全恢复的过程中,iTunes会删除这些文件,因此,您应该能够在必要时重新创建。您可以使用“获取应用程序目录的路径” 部分描述的接口来获取该目录的路径,并对其进行访问。 在iPhone OS 2.2及更高版本,iTunes不对这个目录的内容进行备份。 |
<Application_Home> |
这个目录用于存放临时文件,保存应用程序再次启动过程中不需要的信息。当您的应用程序不再需要这些临时文件时,应该将其从这个目录中删除(系统也可能在应用程序不运行的时候清理留在这个目录下的文件)。有关如何获得这个目录路径的信息,请参见“获取应用程序目录的路径”部分。 在iPhone OS 2.1及更高版本,iTunes不对这个目录的内容进行备份。 |
keychain是一个安全、经过加密保护的容器,用于保存密码和其它秘密信息。应用程序的keychain数据存储在应用程序沙箱之外。如果应用程序被卸载,则该数据会自动被删除。当用户通过iTunes备份应用程序数据时,keychain数据也会被备份。然而,keychain数据只能被恢复到之前做备份的设备上。应用程序的更新并不影响其keychain数据。
iPhone OS提供了如下几种读、写、和管理文件的方法:
Foundation框架:
如果您可以将应用程序数据表示为一个属性列表,则可以用NSPropertyListSerialization
API来将属性列表转换为一个NSData
对象,然后通过NSData
类的方法将数据对象写入磁盘。
如果应用程序的模型对象采纳了NSCoding
协议,则可以通过NSKeyedArchiver
类、特别是它的archivedDataWithRootObject:
方法将模型对象图进行归档。
Foundation框架中的NSFileHandle
类提供了随机访问文件内容的方法。
Foundation框架中的NSFileManager
类提供了在文件系统中创建和操作文件的方法。
Core OS调用:
诸如fopen
、fread
、和fwrite
这些调用可以用于对文件进行顺序或随机读写。
mmap
和
munmap
调用是将大文件载入内存并访问其内容的有效方法。
AAC
ALAC (Apple Lossless)
MP3
下面是一些iPhone OS支持的音频回放格式:
AAC
HE-AAC
AMR (Adaptive Multi-Rate,是一种语音格式)
ALAC (Apple Lossless)
iLBC (互联网Low Bitrate Codec,另一种语音格式)
IMA4 (IMA/ADPCM)
µ-law和a-law
MP3 (MPEG-1 音频第3层)
下面是一些iPhone OS支持的音频录制格式:
ALAC (Apple Lossless)
iLBC (互联网Low Bitrate Codec,用于语音)
IMA/ADPCM (IMA4)
线性PCM
µ-law和a-law
音频会话特性 |
描述 |
---|---|
范畴 |
范畴是标识一组应用程序音频行为的键。您可以通过范畴的设置来指示自己希望得到的音频行为,比如希望在屏幕锁定状态时继续播放音频。 |
中断和路由变化 |
当您的音频发生中断或中断结束,以及当硬件音频路由发生变化时,音频会话会发出通告,使您可以优雅地响应发生在更大音频环境中的变化—比如由于电话呼入而导致的中断。 |
硬件特征 |
您可以通过查询音频会话来了解应用程序所在的设备的特征,比如硬件采样率,硬件通道数量,以及是否有音频输入。 |
举例来说,在使用缺省的音频会话时,如果出现Auto-Lock超时或屏幕锁定,应用程序的音频就会停止。如果您希望在屏幕被锁定时继续播放音频,则必须将下面的代码包含到应用程序的初始化代码中:
[[AVAudioSession sharedInstance] setCategory: AVAudioSessionCategoryPlayback error: nil]; |
[[AVAudioSession sharedInstance] setActive: YES error: nil]; |
音频单元 |
描述 |
---|---|
转换器单元 |
转换器单元,类型为 |
iPod均衡器单元 |
iPod EQ单元,类型为 |
3D混音器单元 |
3D混音器单元,类型为 |
多通道混音器单元 |
多通道混音器单元,类型为 |
一般输出单元 |
一般输出单元,类型为 |
I/O单元 |
I/O单元,类型为 |
语音处理I/O单元 |
语音处理I/O单元,类型为 |
贴士 |
动作 |
---|---|
正确地使用压缩音频 |
对于AAC、MP3、和ALAC (Apple Lossless) 音频,解码过程是由硬件来完成的,虽然比较有效,但同时只能解码一个音频流。如果您需要同时播放多路声音,请使用IMA4 (压缩) 或者线性PCM (无压缩) 格式来存储那些文件。 |
将音频转换为您需要的数据格式和文件格式 |
Mac OS X的 |
评价音频的内存使用问题 |
当您使用音频队列服务播放音频时,需要编写一个回调函数,负责将较短的音频数据片断发送到音频队列的缓冲区。在某些情况下,将整个音频文件载入内存是最佳的选择,这样可以使播放时的磁盘访问尽最少;而在另外一些情况下,最好的方法则是每次只载入足够填满缓冲区的数据。请测试和评价哪种策略对您的应用程序最好。 |
限制音频的采样率和位深度,减少音频文件的尺寸 |
采样率和每个样本的位深度对无压缩音频的尺寸有直接的影响。如果您需要播放很多这样的声音,则应该考虑降低这些指标,以减少音频数据的内存开销。举例来说,相对于使用采样率为44.1 kHz的音频作为声音效果, 您可以使用采样率为32 kHz(或可能更低)的音频,仍然可以得到很合理的品质。 |
选择恰当的技术 |
使用Core Audio的系统声音服务来播放警告和用户界面声音效果。当您希望使用便利的高级接口来定位立体声场中的声音,或者要求很低的回放延迟时,则应该使用OpenAL。如果需要从文件或网络数据流中解析出音频数据,可以使用音频文件服务接口。如果只是简单回放一路或多路声音,则应该使用 |
低延迟编码 |
如果需要尽可能低的回放延迟,可以使用OpenAL,或者直接使用I/O单元。 |
事件频率(Hz) |
用途 |
---|---|
10–20 |
适合用于确定代表设备当前方向的向量。 |
30–60 |
适合用于游戏和使用加速计进行实时输入的应用程序。 |
70–100 |
适合用于需要检测设备高频运动的应用程序,比如检测用户快速触击或摆动设备。 |
如果您需要知道的是设备的大体方向,而不是精确的方向向量,则应该通过UIDevice
类的相关方法来取得。使用UIDevice
接口比较简单,不需要自行计算方向向量。
在取得当前方向之前,您必须调用beginGeneratingDeviceOrientationNotifications
方法,使UIDevice
类开始产生设备方向通告。对该方法的调用会打开加速计硬件(否则为了省电,加速计硬件处于关闭状态)。
在打开方向通告的很短时间后,您就可以从UIDevice
对象orientation
属性声明得到当前的方向。您也可以通过注册接收UIDeviceOrientationDidChangeNotification
通告来得到方向信息,当设备的大体方向发生改变时,系统就会发出该通告。设备的方向由UIDeviceOrientation
常量来描述,它可以指示设备处于景观模式还是肖像模式,以及设备的正面是朝上还是朝下。这些常量指示的是设备的物理方向,不一定和应用程序的用户界面相对应。
UIDevice
的endGeneratingDeviceOrientationNotifications
方法来关闭方向通告,使系统有机会关闭加速计硬件,如果其它地方也不使用的话。
元素类型 |
描述 |
---|---|
文本框 |
文本框类型显示一个可选的标题和一个可编辑的文本输入框,适用于需要用户输入自定义字符串的偏好设置。 这个类型的键是 |
标题 |
标题类型显示一个只读的字符串,适用于显示只读字符串的偏好设置(如果偏好设置包含隐含或非直接的值,这个类型可以将可能的值映射为字符串)。 这个类型的键是 |
拨动开关 |
拨动开关类型显示一个ON/OFF拨动按键,适用于配置值为二选一的偏好设置。这个类型通常用于表示包含布尔值的偏好设置,但也可以用于表示包含非布尔值的偏好设置。 这个类型的键是 |
滑块 |
滑块类型显示一个滑块控件,适用于值为一个范围的偏好设置。这个类型的值是一个实数,值的最小和最大值由您来指定。 这个类型的键是 |
值列表 |
值列表类型使用户可以从一个值的列表中选择其一,适用于支持多个互斥值的偏好设置,这些值的类型可以是任意的。 这个类型的键是 |
组 |
组类型使您可以将几组不同的偏好设置组织到一个页面上。组类型并不表示一个可配置的偏好设置,而只是包含一个标题字符串,显示在一或多个可配置的偏好设置之前。 这个类型的键是 |
子页面 |
子页面类型使用户可以访问新的偏好设置页面,适用于实现多层次的偏好设置。有关如何配置和使用这个类型的更多信息,请参见“多层次的偏好设置” 。这个类型的键是 |
在iPhone OS中,开发者通过一种特殊的Settings程序包来指定应用程序的偏好设置,这种程序包命名为Settings.bundle
,驻留在应用程序程序包的顶级目录上。该程序包中包含一或多个Settings页面文件,用于定义应用程序偏好设置的详细信息;还可以包含显示偏好设置需要的其它支持文件,比如图像或本地化文件。表9-2列出了一个典型Settings程序包的内容。
项目名称 |
描述 |
---|---|
|
这个Settings页面文件包含根页面的偏好设置,它的内容在“Settings页面文件的格式” 部分有更详细的描述。 |
其它 |
如果您需要通过多个子面板来构建一组有层次结构的偏好设置,则每个子面板的内容都分别存储在不同的Settings页面文件中。您需要负责命名这些文件,并将它们关联到正确的子面板上。 |
一或多个 |
这些目录用于存储Settings页面文件的本地化字符串资源。每个目录都包含一个字符串文件,文件的标题在Settings页面中指定。这些字符串文件为偏好设置提供可以直接显示给用户的本地化内容。 |
其它图像 |
如果您使用滑块控件,则可以将滑块的图像存储在程序包的顶级目录下。 |