iOS学习笔记—09硬件调用

一.音频视频播放

1.音频播放

        IOS中有三种播放音频的方式:AVAudioPlayer、音频服务、音频队列。

       此文主要讲AVAudioPlayer,其他两个请见相关文章。

AVAudioPlayer在AVFoundation框架下,所以我们要导入AVFoundation.framework。

AVAudioPlayer类封装了播放单个声音的能力。播放器可以用NSURL或者NSData来初始化,要注意的是NSURL并不可以是网络url而必须是本地文件URL,因为       AVAudioPlayer不具备播放网络音频的能力,不过我们可以用过一点小手段使其具备这个能力,留待稍后讲解。

        一个AVAudioPlayer只能播放一个音频,如果你想混音你可以创建多个AVAudioPlayer实例,每个相当于混音板上的一个轨道。

一、创建一个播放器

[java]  view plain copy print ?
  1. #import <AVFoundation/AVFoundation.h>     
  2. NSError* err;  
  3. AVAudioPlayer* player = [[AVAudioPlayer alloc]  
  4.                         initWithContentsOfURL:[NSURL fileURLWithPath:  
  5.                                               [[NSBundle mainBundle]pathForResource:  
  6.                                            @"music" ofType:@"m4a"   
  7.                                            inDirectory:@"/"]]  
  8.                         error:&err ];//使用本地URL创建  
[java]  view plain copy print ?
  1. AVAudioPlayer* player = [[AVAudioPlayer alloc]  
  2.                             initWithData:myData   
  3.                             error:&err ];//使用NSData创建  

        我之前讲过AVAudioPlayer不可以播放网络URL,但是可以播放NSData,我们似乎受到了点启发,我们可以通过网络URL去创建NSData,然后在通过AVAudioPlayer来播放NSData,这样是不是就可以播放网络音乐了呢?但是此法并不可取,因为AVAudioPlayer只能播放一个完整的文件,并不支持流式播放,所以必须是缓冲完才能播放,所以如果网络文件过大抑或是网速不够岂不是要等很久?所以播放网络音频我们一般用音频队列。

二、播放器属性

        创建一个AVAudioPlayer以后你就可以对它的各种属性进行访问或设置了 。

1.音量

[java]  view plain copy print ?
  1. player.volume=0.8;//0.0~1.0之间  
2.循环次数
[java]  view plain copy print ?
  1. player.numberOfLoops = 3;//默认只播放一次  
3.播放位置
[java]  view plain copy print ?
  1. player.currentTime = 15.0;//可以指定从任意位置开始播放  
4.声道数
[java]  view plain copy print ?
  1. NSUInteger channels = player.numberOfChannels;//只读属性  
5.持续时间
[java]  view plain copy print ?
  1. NSTimeInterval duration = player.dueration;//获取采样的持续时间  

6.仪表计数

[java]  view plain copy print ?
  1. player.meteringEnabled = YES;//开启仪表计数功能  
  2. [ player updateMeters];//更新仪表读数  
  3. //读取每个声道的平均电平和峰值电平,代表每个声道的分贝数,范围在-100~0之间。  
  4. for(int i = 0; i<player.numberOfChannels;i++){  
  5. float power = [player averagePowerForChannel:i];  
  6. float peak = [player peakPowerForChannel:i];  
  7. }  

三、播放声音

        准备了这么久,终于可以播放了,心情激动啊。

[java]  view plain copy print ?
  1. [ player prepareToPlay];//分配播放所需的资源,并将其加入内部播放队列  
  2. [player play];//播放  
  3. [player stop];//停止  

         是否觉得准备了这么久,一下子就结束掉了,太快了,不用急,还有几个重点。

四、代理方法

          加入播放出现异常,或者被更高级别的系统任务打断,我们的程序还没来得及收场就挂了,怎么办?不急,我们可以通过几个委托方法很好地处理所有的情形。

         首先给player设置委托是必须的:

[java]  view plain copy print ?
  1. player.delegate = self;  
[java]  view plain copy print ?
  1. - (void)audioPlayerDidFinishPlaying:(AVAudioPlayer*)player successfully:(BOOL)flag{  
  2.     //播放结束时执行的动作  
  3. }  
  4. - (void)audioPlayerDecodeErrorDidOccur:(AVAudioPlayer*)player error:(NSError *)error{  
  5.     //解码错误执行的动作  
  6. }  
  7. - (void)audioPlayerBeginInteruption:(AVAudioPlayer*)player{  
  8.     //处理中断的代码  
  9. }  
  10. - (void)audioPlayerEndInteruption:(AVAudioPlayer*)player{  
  11.     //处理中断结束的代码  
  12. }  

2.视频播放器

MPMoviePlayerController 与AVAudioPlayer有点类似,前者播放视频,后者播放音频,不过也有很大不同,MPMoviePlayerController 可以直接通过远程URL初始化,而AVAudioPlayer则不可以。不过大体上用起来感觉差不多。废话少说进入体验。
格式支持:MOV、MP4、M4V、与3GP等格式,还支持多种音频格式。
首先你得引入 MediaPlayer.framework.然后在使用到MPMoviePlayerController 的文件中导入相应的头文件。
一、创建
MPMoviePlayerController 类通过一个NSURL来初始化,这个URL可以使本地的,也可以是远程的。初始化需要通过 initWithContentURL 方法来实现:

[html]  view plain copy print ?
  1. MPMoviePlayerController *moviePlayer = [ [ MPMoviePlayerController alloc]initWithContentURL:[NSURL urlWithString:@"http://"] ];//远程  
或者
[html]  view plain copy print ?
  1. NSString* path =[ NSString stringWithFormat:@"%@/Documents/video.3gp",NSHomeDirectory()];//本地路径  
  2. MPMoviePlayerController *moviePlayer = [ [ MPMoviePlayerController alloc]initWithContentURL:[NSURL fileURLWithPath:path]];//本地的  
二、属性设置
1.控制器样式
[html]  view plain copy print ?
  1. moviePlayer.moviewControlMode = MPMovieControlModeDefault;  
可以使用下列样式:
MPMovieControlModeDefault            显示播放/暂停、音量和时间控制
MPMovieControlModeVolumeOnly         只显示音量控制
MPMovieControlModeHidden             没有控制器
2.屏幕宽高比例
[html]  view plain copy print ?
  1. moviePlayer.scallingMode = MPMovieScallingModeAspectFit;  
你可以使用下列宽高比值:
MPMovieScallingModeNone            不做任何缩放
MPMovieScallingModeAspectFit       适应屏幕大小,保持宽高比
MPMovieScallingModeAspectFill      适应屏幕大小,保持宽高比,可裁剪
MPMovieScallingModeFill            充满屏幕,不保持宽高比
3.背景色
背景色会在电影播放器转入转出时使用,当电影不能充满整个屏幕时,也会用来填充空白区域。默认的背景色是黑色,不过你可以使用 UIColor 对象设置backgroundColor属性,来改变背景色:
[html]  view plain copy print ?
  1. moviePlayer.backgroundColor = [UIColor redColor];  
三、播放和停止电影
要播放电影请调用play 方法,电影播放控制器会自动将视图切换到电影播放器并开始播放:
[html]  view plain copy print ?
  1. [ moviePlayer play ];  
当用户点击Done按钮,或者 stop 方法被调用都会停止
[html]  view plain copy print ?
  1. [ moviePlayer stop ];  
当电影停止播放后会自动切回播放前应用程序所在的视图。
四、通知
你的程序可以配置电影播放器在何时候发送通知,包括结束加载内容、技术播放、改变宽高比等。电影播放器会将事件发送到 Cocoa 的通知中心,你可以对其进行配置,指定将这些事件转发到你的应用程序的一个对象。要接收这些通知,需要使用 NSNotificationCenter 类,为电影播放器添加一个观察者(observer):
[html]  view plain copy print ?
  1. NSNotificationCenter* notificationCenter = [NSNotificationCenter defaultCenter];  
  2. [ notificationCenter addObserver:self selector:@selector(moviePlayerPreloadFinish:) name:MPMoviePlayerContentPreloadDidFinishNotification object:moviePlayer ];  
通知会发到你指定的委托类和目标方法。通知参数让你可以知道是哪个事件触发了委托方法:
[html]  view plain copy print ?
  1. -(void)moviePlayerPreloadDidFinish:(NSNotification*)notification{  
  2.     //添加你的处理代码  
  3. }   
你会观察到以下通知:
MPMoviePlayerContentPreloadDidFinishNotification 
当电影播放器结束对内容的预加载后发出。因为内容可以在仅加载了一部分的情况下播放,所以这个通知可能在已经播放后才发出。
MPMoviePlayerScallingModeDidChangedNotification 
当用户改变了电影的缩放模式后发出。用户可以点触缩放图标,在全屏播放和窗口播放之间切换。
MPMoviePlayerPlaybackDidFinishNotification 
当电影播放完毕或者用户按下了Done按钮后发出。

二.照相机和相册的使用

1.打开相机:

[cpp]  view plain copy
  1. //先设定sourceType为相机,然后判断相机是否可用(ipod)没相机,不可用将sourceType设定为相片库  
  2.     UIImagePickerControllerSourceType sourceType = UIImagePickerControllerSourceTypeCamera;  
  3. //    if (![UIImagePickerController isSourceTypeAvailable: UIImagePickerControllerSourceTypeCamera]) {  
  4. //        sourceType = UIImagePickerControllerSourceTypePhotoLibrary;  
  5. //    }  
  6.     //sourceType = UIImagePickerControllerSourceTypeCamera; //照相机  
  7.     //sourceType = UIImagePickerControllerSourceTypePhotoLibrary; //图片库  
  8.     //sourceType = UIImagePickerControllerSourceTypeSavedPhotosAlbum; //保存的相片  
  9.     UIImagePickerController *picker = [[UIImagePickerController alloc] init];//初始化  
  10.     picker.delegate = self;  
  11.     picker.allowsEditing = YES;//设置可编辑  
  12.     picker.sourceType = sourceType;  
  13.     [self presentModalViewController:picker animated:YES];//进入照相界面  
  14.     [picker release];  

2.打开相册:(区分pad和iphone)

for iphone:

[cpp]  view plain copy
  1. UIImagePickerController *pickerImage = [[UIImagePickerController alloc] init];  
  2.     if([UIImagePickerController isSourceTypeAvailable:UIImagePickerControllerSourceTypePhotoLibrary]) {  
  3.         pickerImage.sourceType = UIImagePickerControllerSourceTypePhotoLibrary;  
  4.         //pickerImage.sourceType = UIImagePickerControllerSourceTypeSavedPhotosAlbum;  
  5.         pickerImage.mediaTypes = [UIImagePickerController availableMediaTypesForSourceType:pickerImage.sourceType];  
  6.           
  7.     }  
  8.     pickerImage.delegate = self;  
  9.     pickerImage.allowsEditing = NO;  
  10.     [self presentModalViewController:pickerImage animated:YES];  
  11.     [pickerImage release];  

for ipad:

[cpp]  view plain copy
  1. UIImagePickerControllerSourceType sourceType = UIImagePickerControllerSourceTypePhotoLibrary;  
  2.     //sourceType = UIImagePickerControllerSourceTypeSavedPhotosAlbum; //保存的相片  
  3.     UIImagePickerController *picker = [[UIImagePickerController alloc] init];  
  4.     picker.delegate = self;  
  5.     picker.allowsEditing = NO;//是否允许编辑  
  6.     picker.sourceType = sourceType;  
  7.     /* 
  8.      如果从一个导航按钮处呈现,使用: 
  9.      presentPopoverFromBarButtonItem:permittedArrowDirections:animated:; 
  10.      如果要从一个视图出呈现,使用: 
  11.      presentPopoverFromRect:inView:permittedArrowDirections:animated: 
  12.       
  13.      如果设备旋转以后,位置定位错误需要在父视图控制器的下面方法里面重新定位: 
  14.      didRotateFromInterfaceOrientation:(在这个方法体里面重新设置rect) 
  15.      然后再次调用: 
  16.      - (void)presentPopoverFromRect:(CGRect)rect inView:(UIView *)view permittedArrowDirections:(UIPopoverArrowDirection)arrowDirections animated:(BOOL)animated              
  17.      */  
  18.     //UIPopoverController只能在ipad设备上面使用;作用是用于显示临时内容,特点是总是显示在当前视图最前端,当单击界面的其他地方时自动消失。  
  19.     UIPopoverController *popover = [[UIPopoverController alloc]initWithContentViewController:picker];  
  20.     self.imagePicker = popover;  
  21.     //permittedArrowDirections 设置箭头方向  
  22.     [self.imagePicker presentPopoverFromRect:CGRectMake(0, 0, 300, 300) inView:self.view permittedArrowDirections:UIPopoverArrowDirectionAny animated:YES];  
  23.     [picker release];  
  24.     [popover release];  


点击相册中的图片 或照相机照完后点击use  后触发的方法

- (void)imagePickerController:(UIImagePickerController *)picker didFinishPickingMediaWithInfo:(NSDictionary *)info


点击cancel 调用的方法

- (void)imagePickerControllerDidCancel:(UIImagePickerController *)picker

三.短信 电话和邮件

1、调用 自带mail

[[UIApplication sharedApplication] openURL:[NSURL URLWithString:@"mailto://admin@hzlzh.com"]];

 

2、调用 电话phone

[[UIApplication sharedApplication] openURL:[NSURL URLWithString:@"tel://8008808888"]];

 

3、调用 SMS

[[UIApplication sharedApplication] openURL:[NSURL URLWithString:@"sms://800888"]];

 

4、调用自带 浏览器 safari

[[UIApplication sharedApplication] openURL:[NSURL URLWithString:@"http://www.hzlzh.com"]];

 

调用phone可以传递号码,调用SMS 只能设定号码,不能初始化SMS内容。

 

若需要传递内容可以做如下操作:

加入:MessageUI.framework

 

#import <MessageUI/MFMessageComposeViewController.h>

 

实现代理:MFMessageComposeViewControllerDelegate


调用sendSMS函数

//内容,收件人列表

- (void)sendSMS:(NSString *)bodyOfMessage recipientList:(NSArray *)recipients

{

 

    MFMessageComposeViewController *controller = [[[MFMessageComposeViewController allocinitautorelease];

 

    if([MFMessageComposeViewController canSendText])

 

    {

 

        controller.body = bodyOfMessage;   

 

        controller.recipients = recipients;

 

        controller.messageComposeDelegate = self;

 

        [self presentModalViewController:controller animated:YES];

 

    }   

 

}

 

// 处理发送完的响应结果
- (void)messageComposeViewController:(MFMessageComposeViewController *)controller didFinishWithResult:(MessageComposeResult)result
{
  [self dismissModalViewControllerAnimated:YES];
 
  if (result == MessageComposeResultCancelled)
    NSLog(@"Message cancelled")
  else if (result == MessageComposeResultSent)
    NSLog(@"Message sent")  
  else 
    NSLog(@"Message failed")  
}

 

 

发送邮件的为:

导入#import <MessageUI/MFMailComposeViewController.h>

实现代理:MFMailComposeViewControllerDelegate

 

//发送邮件

-(void)sendMail:(NSString *)subject content:(NSString *)content{

 

    MFMailComposeViewController *controller = [[[MFMailComposeViewController allocinitautorelease];

 

    if([MFMailComposeViewController canSendMail])

 

    {

 

        [controller setSubject:subject];

 

        [controller setMessageBody:content isHTML:NO];

 

        controller.mailComposeDelegate = self;

 

        [self presentModalViewController:controller animated:YES];

 

    }    

}

 

//邮件完成处理

-(void)mailComposeController:(MFMailComposeViewController *)controller didFinishWithResult:(MFMailComposeResult)result error:(NSError *)error{

 

    [self dismissModalViewControllerAnimated:YES];

 

    if (result == MessageComposeResultCancelled)

        NSLog(@"Message cancelled");

    else if (result == MessageComposeResultSent)

        NSLog(@"Message sent"); 

    else 

        NSLog(@"Message failed");  

 

}

 

四.地图和定位

iOS上使用地图只需要新建一个MKMapView,addSubView即可。这次要实现的效果如下:


有标注(大头针),定位,地图。

1、添加地图

1.1 新一个Single View app ,选择默认项,创建后,在ViewController.h 

[cpp]  view plain copy
  1. #import <UIKit/UIKit.h>  
  2. #import <MapKit/MapKit.h>  
  3. #import <CoreLocation/CoreLocation.h>  
  4.   
  5. @interface ViewController : UIViewController   
  6. <MKMapViewDelegate, CLLocationManagerDelegate> {  
  7.     MKMapView *map;  
  8.     CLLocationManager *locationManager;  
  9. }  
  10. @end  

1.2在ViewController.m中添加

[cpp]  view plain copy
  1. - (void)viewDidLoad  
  2. {  
  3.     map = [[MKMapView alloc] initWithFrame:[self.view bounds]];  
  4.     map.showsUserLocation = YES;  
  5.     map.mapType = MKMapTypeSatellite;  
  6.     [self.view addSubview:map];  
  7.   
  8.   
  9.     [super viewDidLoad];  
  10.     // Do any additional setup after loading the view, typically from a nib.  
  11. }  

运行:

OMG,看到的是世界地图。怎么定位到指定的位置呢?比如定位回来伟大的祖国首都?

这里map.mapType =MKMapTypeSatellite;我用到是卫星地图,可以使用标准的地图,

map.mapType =MKMapTypeStandard;


注意,如果此时你编译有错误,请拉到博客最后查看 :5、 遇到的问题

2、定位到指定经纬度

[cpp]  view plain copy
  1. CLLocationCoordinate2D coords = CLLocationCoordinate2DMake(39.915352,116.397105);  
  2.       
  3.     float zoomLevel = 0.02;  
  4.     MKCoordinateRegion region = MKCoordinateRegionMake(coords, MKCoordinateSpanMake(zoomLevel, zoomLevel));  
  5.     [map setRegion:[map regionThatFits:region] animated:YES];  
  6.           

这样,就我们就定位的了故宫了。


3、添加标注大头针

3.1 新建一个标注类:CustomAnnotation

按Command+N,继承NSObject。在CustomAnnotation.h 和CustomAnnotation.m文件添加如下代码:

[cpp]  view plain copy
  1. #import <Foundation/Foundation.h>  
  2. #import <MapKit/MapKit.h>  
  3.   
  4. @interface CustomAnnotation : NSObject   
  5. <MKAnnotation>  
  6. {  
  7.     CLLocationCoordinate2D coordinate;  
  8.     NSString *title;  
  9.     NSString *subtitle;  
  10. }  
  11. -(id) initWithCoordinate:(CLLocationCoordinate2D) coords;  
  12.   
  13. @property (nonatomic, readonly) CLLocationCoordinate2D coordinate;  
  14. @property (nonatomic, retain) NSString *title;  
  15. @property (nonatomic, retain) NSString *subtitle;  
  16.   
  17. @end  
[cpp]  view plain copy
  1. #import "CustomAnnotation.h"  
  2.   
  3. @implementation CustomAnnotation  
  4. @synthesize coordinate, title, subtitle;  
  5.   
  6. -(id) initWithCoordinate:(CLLocationCoordinate2D) coords  
  7. {  
  8.     if (self = [super init]) {  
  9.         coordinate = coords;  
  10.     }  
  11.     return self;  
  12. }  
  13. @end  

3.1 使用大头针,

新建个方法添加大头针的

[cpp]  view plain copy
  1. -(void)createAnnotationWithCoords:(CLLocationCoordinate2D) coords {  
  2.     CustomAnnotation *annotation = [[CustomAnnotation alloc] initWithCoordinate:   
  3.                                     coords];  
  4.     annotation.title = @"标题";  
  5.     annotation.subtitle = @"子标题";  
  6.     [map addAnnotation:annotation];  
  7. }  

调用

[cpp]  view plain copy
  1. CLLocationCoordinate2D coords = CLLocationCoordinate2DMake(39.915352,116.397105);  
  2.       
  3.     float zoomLevel = 0.02;  
  4.     MKCoordinateRegion region = MKCoordinateRegionMake(coords, MKCoordinateSpanMake(zoomLevel, zoomLevel));  
  5.     [map setRegion:[map regionThatFits:region] animated:YES];  
  6.   
  7.       
  8.     [self createAnnotationWithCoords:coords];  
这样我们就把大头针定位在故宫了



4、定位到当前位置并获取当前经纬度

前面我们已经添加了locationManager,现在在DidViewLoad里直接调用

[cpp]  view plain copy
  1. locationManager = [[CLLocationManager alloc] init];  
  2.     locationManager.delegate = self;  
  3.     [locationManager startUpdatingLocation];  


实现协议方法收到定位成功后的经纬度

[cpp]  view plain copy
  1. - (void)locationManager:(CLLocationManager *)manager didUpdateToLocation:(CLLocation *)newLocation fromLocation:(CLLocation *)oldLocation {  
  2.     [locationManager stopUpdatingLocation];  
  3.       
  4.     NSString *strLat = [NSString stringWithFormat:@"%.4f",newLocation.coordinate.latitude];  
  5.     NSString *strLng = [NSString stringWithFormat:@"%.4f",newLocation.coordinate.longitude];  
  6.     NSLog(@"Lat: %@  Lng: %@", strLat, strLng);  
  7.   
  8. }  
  9.   
  10. - (void)locationManager:(CLLocationManager *)manager didFailWithError:(NSError *)error {  
  11.     NSLog(@"locError:%@", error);  
  12.   
  13. }  

运行,允许获取当前位置,打印log

[cpp]  view plain copy
  1. 2012-06-28 23:58:32.237 MapDemo[8202:11603] Lat: 39.9011  Lng: 116.3000  
如果不允许:打印出错误日志

[cpp]  view plain copy
  1. 2012-06-28 23:25:03.109 MapDemo[7531:11603] locError:Error Domain=kCLErrorDomain Code=1 "The operation couldn’t be completed. (kCLErrorDomain error 1.)"  

定位后,移动到当前位置:

[cpp]  view plain copy
  1. - (void)locationManager:(CLLocationManager *)manager didUpdateToLocation:(CLLocation *)newLocation fromLocation:(CLLocation *)oldLocation {  
  2.     [locationManager stopUpdatingLocation];  
  3.       
  4.     NSString *strLat = [NSString stringWithFormat:@"%.4f",newLocation.coordinate.latitude];  
  5.     NSString *strLng = [NSString stringWithFormat:@"%.4f",newLocation.coordinate.longitude];  
  6.     NSLog(@"Lat: %@  Lng: %@", strLat, strLng);  
  7.       
  8.     CLLocationCoordinate2D coords = CLLocationCoordinate2DMake(newLocation.coordinate.latitude,newLocation.coordinate.longitude);  
  9.     float zoomLevel = 0.02;  
  10.     MKCoordinateRegion region = MKCoordinateRegionMake(coords,MKCoordinateSpanMake(zoomLevel, zoomLevel));  
  11.     [map setRegion:[map regionThatFits:region] animated:YES];  
  12. }  


定位到了当前位置。

五.加速计和陀螺仪

 1.访问加速计
UIAccelerometer类是单独存在的。要获取对此类的引用,请调用sharedAccelerometer方法:

UIAccelerometer *accelerometer=[UIAccelerometer sharedAccelerometer];

从加速计获取信息与从Core Location获取信息相似。创建一个符合UIAccelerometerDelegate协议的类,执行可以获取加速计信息的方法。
在分配委托时,需要以秒指定更新间隔。iPhone的加速计支持最高以每秒100次的频率进行轮询,但无法保证真正达到这么多次更新,或者可以精确均匀分隔这些更新。要分配委托或指定轮询间隔为每秒60次,可以如下所示:

accelerometer.delegate=self;
accelerometer.updateInterval=1.0f/60.0f;

完成之后,剩余的事情是实现加速计用于更新委托的方法,accelerometer:didAccelerate:。第二个变量包含了来自加速计的真实数据,嵌入在类UIAcceleration的一个对象中。

 UIAcceleration
如前所述,iPhone加速计可以检测3个轴上的加速度,并且对使用UIAcceleration类实例的委托提供此信息。每个UIAcceleration实例都有x、y和z的属性,分别有一个带符号的浮点值。值0表示加速计在此轴上没有检测到任何运动。正值或负值表示一个方向上的力。例如,y的负值表示感受到了向下的力,这可能表示电话是纵向竖直握持的。y的正值表示在向上的方向施加了某些力,这可能意味着电话是倒置的或者电话正在向下运动。(这里有点疑问?说反了吧?)
请在头脑中牢记图15-1的示意图,并查看加速计结果。注意,在现实生活中,几乎不可能获得如此精确的值,因为加速计非常敏感,可以感知非常微笑的运动,而我们通常只能感知立体空间3个轴上的某一个微小受力。这是现实世界中的物理,而不是高中物理实验室。

iPhone开发基础教程笔记(十五)--第十五章 加速计 - supershll - 记忆里

 实现accelerometer:didAccelertae:方法

- (void)accelerometer:(UIAccelerometer *)accelerometer didAccelerate:(UIAcceleration *)acceleration {
NSString *newText=[[NSString alloc] initWithFormat:@"Max: x: %g\ty:%g\tz:

%g",acceleration.x,acceleration.y,acceleration.z];
label.text=newText;
[newText release];
}

此方法可以在每次调用时更改界面上的标签,调用此方法的频率取决于以前指定的updateInterval的值。

1,检测摇动
加速计通常用于检测摇动。与手势相似,摇动可以作为应用程序输入的一种形式。例如,对于绘图程序GLPaint,iPhone的示例代码之一,用户可以通过摇动iPhone擦除绘图,就像Etch-a-Sketch一样。摇动检测功能相对来说是微不足道的,主需要检查某个轴上的绝对值是否大于阈值(yu)。在正常使用期间,3个轴之一所注册的值通常在1.3g左右,若要远高于此值,则需要刻意施加力量。加速计好像不能注册高于2.3g左右的值。因此,请勿将阈值设置得高于此值。

要检测摇动,请检查绝对值是否大于1.5(表示轻微摇动)和2.0(表示剧烈摇动),代码如下:

- (void)accelerometer:(UIAccelerometer *)accelerometer didAccelerate:(UIAcceleration *)acceleration {
if (fbasf(acceleration.x)>2.0 || fbasf(acceleration.y)>2.0 || fbasf(acceleration.z)>2.0 ) {
//do something here...
}
}

上述方法可以检测到任一轴上任何超过2g力的运动。通过要求用户前后摇动一定次数才能注册为一次摇动,我们可以执行更复杂的摇动检测,代码如下:

- (void)accelerometer:(UIAccelerometer *)accelerometer didAccelerate:(UIAcceleration *)acceleration {
static NSInteger shakeCount=0;
static NSDate *shakeStart;

NSDate *now=[[NSDate alloc] init];
NSDate *checkDate=[[NSDate alloc] initWithTimeInterval:1.5f sinceDate:shakeStart];

if ([now compare:checkDate]==NSOrderedDescending || shakeStart ==nil) {
shakeCount=0;
[shakeStart release];
shakeStart=[[NSDate alloc] init];
}
[now release];
[checkDate release];

if (fbasf(acceleration.x)>2.0 || fbasf(acceleration.y)>2.0 || fbasf(acceleration.z)>2.0 ) {
shakeCount++;
if (shakeCount>4) {
//do something
shakeCount=0;
[shakeStart release];
shakeStart=[[NSDate alloc] init];
}
}
}

此方法可以查明加速计报告的值大于2的次数,如果在1.5s的时间内发送了4次,则注册为一次摇动。


2.加速计用作方向控制器
或许加速计在第三方应用程序中最常见的用法是作为游戏控制器。在游戏中不是使用按钮控制字符或对象的移动,而是使用加速计。例如,在赛车游戏中,像转动方向盘那样转到iPhone也许就可以驾驶汽车,而向前倾斜表示加速,向后倾斜表示刹车。
具体如何将加速计用作控制器,这很大程度上取决于游戏的特定机制。在很简单的情况下,可能只需要获取一个轴的值,乘以某个数,然后添加到所控制对象的坐标系中。
使用加速计作为控制器的一个棘手问题是,委托方法并不能保证以指定的间隔回调。如果告诉加速计每秒钟更新60次委托类,所能确定的仅仅是他每秒钟更新的次数绝对不会多于60次。因此不能保证每秒钟得到60次均匀分隔的更新,所以如果所做的动画是基于来自加速计的输入,那么必须要弄清楚委托方法调用之间的时间。

说明 本章中的应用程序在仿真器上不起作用,因为仿真器中没有加速计。

摇动与击碎
我们要编写一个应用程序,他在检测到摇动之后会使电话看起来和听起来好像他因为摇动而破碎一样。启动此应用程序后,程序会显示一张图片,他看起来像是iPhone的首页。
摇动电话时,发出破碎的声音,并更换图片。
然后只需触摸屏幕,就可以重置其初始状态。

 用于击碎的代码
创建一个基于视图的项目 ShakeAndBreak。在 15 ShakeAndBreak文件夹中找到两张图像和一个声音文件,拖到Resources文件夹中。还有一个icon.png,也添加到Resources文件夹。
展开Resources文件夹中的info.plist,在属性列表中添加一个条目,告诉应用程序不要使用状态栏。单击Information Property List行,单击出现在本行末端的按钮,添加一个新的子值,将新行的Key改为UIStatusBarHidden,然后在右键单击刚才添加的行的空Value列。此时应该出现一个上下文菜单,选择ValueType为Boolean。此行应该变为一个复选框,单击选中此复选框。最后,修改Icon File为icon.png。

然后,展开Classes文件,单击ShakeAndBreakViewController.h:

#define kAccelerationThreshold 2.2
#define kUpdateInterval (1.0f/10.0f)

#import <AudioToolbox/AudioToolbox.h>

@interface ShakeAndBreakViewController:UIViewController <UIAccelerometerDelegate> {
IBOutlet UIImageView *imageView;
BOOL brokenScreenShowing;
SystemSoundId soundID;
UIImage *fixed;
UIIMage *broken;
}
@property ..
@end

我们定义更新频率为1s 10次,这已经足够检测到一次摇动。通常来说,轮询时会使用能满足要求的最低频率。在将加速计用作控制器时,需要以相当快的速率轮询,通常达到每秒30次到60次更新。

打开ShakeAndBreakViewController.xib。单击View图标,Cmd+3 修改其大小,高度460=》480,将Image View从库中拖到View窗口中。

单击ShakeAndBreakViewController.m:

- (void)viewDidLoad {
UIAccelerometer *accel=[UIAccelerometer sharedAccelerometer];
accel.delegate=self;
accel.updateInterval=kUpdateInterval;

NSString *path=[[NSBundle mainBundle] pathForResource:@"glass" ofType:@"wav"];
AudioServicesCreateSystemSoundID((CFURLRef)[NSURL fileURLWithPath:path],&soundID);

self.fixed=[UIImage imageNamed:@"home.png"];
self.broken=[UIImage imageNamed:@"homebroken.png"];

imageView.image=fixed;
brokenScreenShowing=NO;
}

- (void)accelerometer:(UIAccelerometer *)accelerometer didAccelerate:(UIAcceleration *)acceleration {
if (! brokenScreenShowing) {
if (acceleration.x >kAccelerationThreshold || acceleration.y >kAccelerationThreshold || acceleration.z

>kAccelerationThreshold) {
imageView.image=broken;
AudioServicePlaySystemSound(soundID);
brokenScreenShowing=YES;
}
}
}
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
imageView.image=fixed;
brokenScreenShowing=NO;
}
@end


2.陀螺仪

以前在iphone中要得到加速度时,只能使用Accelerometer模块得到重力加速度分量,然后通过滤波得到加速度值。其实在ios中有一个陀螺仪模块,CoreMotion,使用更方便。

CoreMotion中主要有以下几个模块


初始化CoreMotion

[html]  view plain copy
  1. #import <CoreMotion/CoreMotion.h>  
  2.   
  3. CMMotionManager *motionManager = [[CMMotionManager alloc]init];  

1. Accelerometer 获取手机加速度数据

[html]  view plain copy
  1. CMAccelerometerData *newestAccel = motionManager.accelerometerData;  
  2. double accelerationX = newestAccel.acceleration.x;  
  3. double accelerationY = newestAccel.acceleration.y;  
  4. double accelerationZ = newestAccel.acceleration.z;  

2. Gravity 获取手机的重力值在各个方向上的分量,根据这个就可以获得手机的空间位置,倾斜角度等

[html]  view plain copy
  1. double gravityX = motionManager.deviceMotion.gravity.x;  
  2. double gravityY = motionManager.deviceMotion.gravity.y;  
  3. double gravityZ = motionManager.deviceMotion.gravity.z;  

获取手机的倾斜角度:

[html]  view plain copy
  1. double zTheta = atan2(gravityZ,sqrtf(gravityX*gravityX+gravityY*gravityY))/M_PI*180.0;  
  2.   
  3. double xyTheta = atan2(gravityX,gravityY)/M_PI*180.0;  

zTheta是手机与水平面的夹角, xyTheta是手机绕自身旋转的角度


3. DeviceMotion 获取陀螺仪的数据 包括角速度,空间位置等

旋转角速度:

[html]  view plain copy
  1. CMRotationRate rotationRate = motionManager.deviceMotion.rotationRate;  
  2. double rotationX = rotationRate.x;  
  3. double rotationY = rotationRate.y;  
  4. double rotationZ = rotationRate.z;  

空间位置的欧拉角(通过欧拉角可以算得手机两个时刻之间的夹角,比用角速度计算精确地多)

[html]  view plain copy
  1. double roll    = motionManager.deviceMotion.attitude.roll;  
  2. double pitch   = motionManager.deviceMotion.attitude.pitch;  
  3. double yaw     = motionManager.deviceMotion.attitude.yaw;  

空间位置的四元数(与欧拉角类似,但解决了万向结死锁问题)
[html]  view plain copy
  1. double w = motionManager.deviceMotion.attitude.quaternion.w;  
  2. double wx = motionManager.deviceMotion.attitude.quaternion.x;  
  3. double wy = motionManager.deviceMotion.attitude.quaternion.y;  
  4. double wz = motionManager.deviceMotion.attitude.quaternion.z;  

通过陀螺仪模块可以实现模拟赛车,模拟射击等。



 






评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值