通讯录 、 传感器

1 系统通讯录

1.1 问题

移动设备提供了一个很重要的的内置数据库——通讯录,通讯录放在SQLite3数据库中,但是应用之间不能直接访问,也就是其他的应用不能采用持久化技术直接访问通讯录数据库,为了实现通讯录数据库的访问,苹果开放了一些专门的API,在开发访问通讯录的应用中通常使用两个框架:AddressBook和AddressBookUI。本案例使用AddressBook框架和AddressBookUI框架实现对系统通讯录联系人的访问和编辑,如图-1所示:

图-1

1.2 方案

首先创建一个SingleViewApplication应用,在Storyboard文件中搭建选取联系人的界面,本案例中的场景是一个带有导航的TableViewController和ViewController进行绑定,标题设置为My Friend。

然后分别给左右两边拖放一个BarButtonItem控件,关联成ViewController的动作方法selectContacts:和newClick:,左边按钮的动作方法用于实现访问系统通讯录选择联系人,右边按钮的动作方法用于创建新联系人。

界面完成后在ViewController中定义两个属性NSMutableArray类型的属性contactNames和contactIDs,分别用于记录当前界面需要展示的联系人姓名和联系人ID,然后实现表视图的数据源方法,展示My Friend界面的联系人姓名。

然后实现selectContacts:方法,当点击左上角按钮时创建ABPeoplePickerNavigationController视图控制器对象peoplePicker,访问系统通讯录的联系人,并设置peoplePicker的委托对象。

实现ABPeoplePickerNavigationControllerDelegate协议中的方法peoplePickerNavigationController:didSelectPerson:,该方法会在选择完联系人时调用,因此该方法需要获取到所选联系人的姓名和ID,并将选中的联系人姓名展示在My Friend界面中。

接下来需要实现当用户点击My Friend界面的联系人姓名时,则展示该联系人的详细信息,因此需要在tableView:didSelectRowAtIndexPath:方法中创建ABPersonViewController视图控制器对象personViewController,并设置委托对象,然后展示出来。

ABPersonViewControllerDelegate有一个必须实现的方法personViewController:shouldPerformDefaultActionForPerson:property:该方法在选择联系人属性时被调用,返回YES则调用该属性的默认动作,返回NO则不做任何动作。

最后实现新建联系人方法newClick:,该方法中需要创建ABNewPersonViewController视图控制器对象newPersonViewController,用于展示新建联系人界面,并设置委托对象。ABNewPersonViewControllerDelegate协议有一个必须实现的方法newPersonViewController:didCompleteWithNewPerson:,该方法在联系人新建完成之后调用,本案例需要在该方法将联系人的联系人的姓名和ID记录下来,并将选中的联系人姓名展示在My Friend界面中。

1.3 步骤

实现此案例需要按照如下步骤进行。

步骤一:搭建界面

首先创建一个SingleViewApplication应用,在Storyboard文件中搭建选取联系人的界面,本案例中的场景是一个带有导航的TableViewController和ViewController进行绑定,标题设置为My Friend。

然后分别给左右两边拖放一个BarButtonItem控件,关联成ViewController的动作方法selectContacts:和newClick:,左边按钮的动作方法用于实现访问系统通讯录选择联系人,右边按钮的动作方法用于创建新联系人。

在Storyboard中完成的界面如图-2所示:

图-2

步骤二:选择联系人

界面完成后在ViewController中定义两个属性NSMutableArray类型的属性contactNames和contactIDs,分别用于记录当前界面需要展示的联系人姓名和联系人ID,并使用延迟加载方式初始化这两个属性,代码如下所示:

  1. @interface ViewController ()
  2. //保存联系人姓名数组属性
  3. @property(nonatomic, strong) NSMutableArray *contactNames;
  4. //保存联系人ID数组属性
  5. @property(nonatomic, strong) NSMutableArray *contactIDs;
  6. @end
  7. //初始化
  8. -(NSMutableArray *)contactIDs {
  9. if (!_contactIDs) {
  10. _contactIDs = [@[]mutableCopy];
  11. }
  12. return _contactIDs;
  13. }
  14. -(NSMutableArray *)contactNames {
  15. if (!_contactNames) {
  16. _contactNames = [@[]mutableCopy];
  17. }
  18. return _contactNames;
  19. }

然后实现表视图的数据源方法,展示My Friend界面的联系人姓名,代码如下所示:

  1. - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
  2. return self.contactNames.count;
  3. }
  4. - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
  5. static NSString *CellIdentifier = @"Cell";
  6. UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
  7. if (cell == nil) {
  8. cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier];
  9. }
  10. cell.accessoryType = UITableViewCellAccessoryDisclosureIndicator;
  11. cell.textLabel.text = [self.contactNames objectAtIndex:[indexPath row]];
  12. return cell;
  13. }

接下来实现通过系统通讯录选择联系人的方法selectContacts:,当点击左上角按钮时创建ABPeoplePickerNavigationController视图控制器对象peoplePicker,访问系统通讯录的联系人,并设置peoplePicker的委托对象,代码如下所示:

  1. //选择联系人
  2. - (IBAction)selectContacts:(id)sender
  3. {
  4. //创建ABPeoplePickerNavigationController控制器,用于访问通讯录显示联系人列表
  5. ABPeoplePickerNavigationController *peoplePicker = [[ABPeoplePickerNavigationController alloc] init];
  6. peoplePicker.peoplePickerDelegate = self;
  7. [self presentViewController:peoplePicker animated:YES completion:nil];
  8. }

最后需要实现ABPeoplePickerNavigationControllerDelegate协议中的方法peoplePickerNavigationController:didSelectPerson:,该方法会在选择完联系人时调用,因此该方法需要获取到所选联系人的姓名和ID,并将选中的联系人姓名展示在My Friend界面中,代码如下所示:

  1. //选择联系人时调用
  2. - (void)peoplePickerNavigationController:(ABPeoplePickerNavigationController*)peoplePicker didSelectPerson:(ABRecordRef)person {
  3. //获取选择联系人的姓名
  4. NSString *name = CFBridgingRelease(ABRecordCopyCompositeName(person));
  5. //将姓名添加到self.contactNames数组
  6. [self.contactNames addObject:name];
  7. //获取ID,将ID添加到self.contactIDs数组
  8. [self.contactIDs addObject:[NSNumber numberWithInt:ABRecordGetRecordID(person)]];
  9. //peoplePicker界面退回
  10. [peoplePicker dismissViewControllerAnimated:YES completion:nil];
  11. //取得最后一个放入contactIDs中的ID,也就是刚刚选择的ID
  12. NSIndexPath *path = [NSIndexPath indexPathForRow:self.contactIDs.count-1 inSection:0];
  13. //选中联系人插入到首页表视图中
  14. NSArray *arry = [NSArray arrayWithObject:path];
  15. [self.tableView insertRowsAtIndexPaths:arry withRowAnimation:UITableViewRowAnimationRight];
  16. }

当点击Cancel按钮时系统通讯录的联系人界面退出,代码如下所示:

  1. //点击Cancel按钮时调用
  2. - (void)peoplePickerNavigationControllerDidCancel:(ABPeoplePickerNavigationController *)peoplePicker
  3. {
  4. [peoplePicker dismissViewControllerAnimated:YES completion:nil];
  5. }

完成效果如图-3,图-4所示:

图-3

图-4

步骤三:显示联系人详细信息

当用户点击My Friend界面的联系人姓名时,则展示该联系人的详细信息,因此需要在tableView:didSelectRowAtIndexPath:方法中创建ABPersonViewController视图控制器对象personViewController,并设置委托对象然后展示出来,注意如果需要对联系人进行编辑需要将allowsEditing属性设置为YES,左上角才会出现编辑按钮否则不能进行编辑,代码如下所示:

  1. - (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
  2. CFErrorRef error = NULL;
  3. //创建addressBook对象
  4. ABAddressBookRef addressBook = ABAddressBookCreateWithOptions(NULL, &error);
  5. //通过ID得到记录对象
  6. ABRecordRef person = ABAddressBookGetPersonWithRecordID(addressBook, [[self.contactIDs objectAtIndex:indexPath.row] intValue]);
  7. //创建ABPersonViewController控制器,用于显示和编辑联系人详细信息
  8. ABPersonViewController *personViewController = [[ABPersonViewController alloc] init];
  9. //设置委托对象
  10. personViewController.personViewDelegate = self;
  11. //设定要显示的联系人对象
  12. personViewController.displayedPerson = person;
  13. //设定联系人视图是否可以编辑
  14. personViewController.allowsEditing = YES;
  15. //是否显示动作按钮
  16. personViewController.allowsActions = YES;
  17. //设置需要显示的属性,邮箱和电话
  18. personViewController.displayedProperties = @[[NSNumber numberWithInt:kABPersonEmailProperty],
  19. [NSNumber numberWithInt:kABPersonPhoneProperty]];
  20. [self.navigationController pushViewController:personViewController animated:YES];
  21. CFRelease(addressBook);
  22. }

ABPersonViewControllerDelegate有一个必须实现的方法personViewController:shouldPerformDefaultActionForPerson:property:该方法在选择联系人属性时被调用,返回YES则调用该属性的默认动作,返回NO则不做任何动作,代码如下所示:

  1. - (BOOL)personViewController:(ABPersonViewController *)personViewController
  2. shouldPerformDefaultActionForPerson:(ABRecordRef)person
  3. property:(ABPropertyID)property identifier:(ABMultiValueIdentifier)identifierForValue
  4. {
  5. return YES;
  6. }

完成效果如图-5所示:

图-5

步骤四:新建联系人

实现新建联系人方法newClick:,该方法中需要创建ABNewPersonViewController视图控制器对象newPersonViewController,用于展示新建联系人界面,并设置委托对象,代码如下所示:

  1. - (IBAction)newClick:(id)sender {
  2. //创建ABNewPersonViewController控制器,用于新建联系人
  3. ABNewPersonViewController *newPersonViewController = [[ABNewPersonViewController alloc] init];
  4. //设置委托对象
  5. newPersonViewController.newPersonViewDelegate = self;
  6. UINavigationController *newNavigationController = [[UINavigationController alloc]
  7. initWithRootViewController:newPersonViewController];
  8. [self presentViewController:newNavigationController animated:YES completion:nil];
  9. }

ABNewPersonViewControllerDelegate协议有一个必须实现的方法newPersonViewController:didCompleteWithNewPerson:,该方法在联系人新建完成之后调用,本案例需要在该方法将联系人的联系人的姓名和ID记录下来,并将选中的联系人姓名展示在My Friend界面中,代码如下所示:

  1. - (void)newPersonViewController:(ABNewPersonViewController *)newPersonView
  2. didCompleteWithNewPerson:(ABRecordRef)person
  3. {
  4. NSString *name = CFBridgingRelease(ABRecordCopyCompositeName(person));
  5. [self.contactNames addObject:name];
  6. [self.contactIDs addObject:[NSNumber numberWithInt:ABRecordGetRecordID(person)]];
  7. [newPersonView dismissViewControllerAnimated:YES completion:nil];
  8. //取得最后一个放入contactIDs中的ID,也就是刚刚选择的ID
  9. NSIndexPath *path = [NSIndexPath indexPathForRow:self.contactIDs.count-1 inSection:0];
  10. //选中联系人插入到首页表视图中
  11. NSArray *arry = [NSArray arrayWithObject:path];
  12. [self.tableView insertRowsAtIndexPaths:arry withRowAnimation:UITableViewRowAnimationRight];
  13. }

新建的联系人会被添加到系统通讯录中,效果如图-6,图-7所示:

图-6

图-7

1.4 完整代码

本案例中,TRViewController.m文件中的完整代码如下所示:

  1. #import "ViewController.h"
  2. #import <AddressBook/AddressBook.h>
  3. #import <AddressBookUI/AddressBookUI.h>
  4. @interface ViewController ()<ABPeoplePickerNavigationControllerDelegate,ABPersonViewControllerDelegate,ABNewPersonViewControllerDelegate>
  5. //保存联系人姓名数组属性
  6. @property(nonatomic, strong) NSMutableArray *contactNames;
  7. //保存联系人ID数组属性
  8. @property(nonatomic, strong) NSMutableArray *contactIDs;
  9. @end
  10. @implementation ViewController
  11. -(NSMutableArray *)contactIDs {
  12. if (!_contactIDs) {
  13. _contactIDs = [@[]mutableCopy];
  14. }
  15. return _contactIDs;
  16. }
  17. -(NSMutableArray *)contactNames {
  18. if (!_contactNames) {
  19. _contactNames = [@[]mutableCopy];
  20. }
  21. return _contactNames;
  22. }
  23. #pragma mark -
  24. #pragma mark 表视图数据源
  25. - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
  26. return self.contactNames.count;
  27. }
  28. - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
  29. static NSString *CellIdentifier = @"Cell";
  30. UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
  31. if (cell == nil) {
  32. cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier];
  33. }
  34. cell.accessoryType = UITableViewCellAccessoryDisclosureIndicator;
  35. cell.textLabel.text = [self.contactNames objectAtIndex:[indexPath row]];
  36. return cell;
  37. }
  38. - (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
  39. CFErrorRef error = NULL;
  40. //创建addressBook对象
  41. ABAddressBookRef addressBook = ABAddressBookCreateWithOptions(NULL, &error);
  42. //通过ID得到记录对象
  43. ABRecordRef person = ABAddressBookGetPersonWithRecordID(addressBook, [[self.contactIDs objectAtIndex:indexPath.row] intValue]);
  44. //创建ABPersonViewController控制器,用于显示和编辑联系人详细信息
  45. ABPersonViewController *personViewController = [[ABPersonViewController alloc] init];
  46. //设置委托对象
  47. personViewController.personViewDelegate = self;
  48. //设定要显示的联系人对象
  49. personViewController.displayedPerson = person;
  50. //设定联系人视图是否可以编辑
  51. personViewController.allowsEditing = YES;
  52. //是否显示动作按钮
  53. personViewController.allowsActions = YES;
  54. //设置需要显示的属性,邮箱和电话
  55. personViewController.displayedProperties = @[[NSNumber numberWithInt:kABPersonEmailProperty],
  56. [NSNumber numberWithInt:kABPersonPhoneProperty]];
  57. [self.navigationController pushViewController:personViewController animated:YES];
  58. CFRelease(addressBook);
  59. }
  60. //新建联系人
  61. - (IBAction)newClick:(id)sender {
  62. //创建ABNewPersonViewController控制器,用于新建联系人
  63. ABNewPersonViewController *newPersonViewController = [[ABNewPersonViewController alloc] init];
  64. //设置委托对象
  65. newPersonViewController.newPersonViewDelegate = self;
  66. UINavigationController *newNavigationController = [[UINavigationController alloc]
  67. initWithRootViewController:newPersonViewController];
  68. [self presentViewController:newNavigationController animated:YES completion:nil];
  69. }
  70. //选择联系人
  71. - (IBAction)selectContacts:(id)sender
  72. {
  73. //创建ABPeoplePickerNavigationController控制器,用于访问通讯录显示联系人列表
  74. ABPeoplePickerNavigationController *peoplePicker = [[ABPeoplePickerNavigationController alloc] init];
  75. peoplePicker.peoplePickerDelegate = self;
  76. [self presentViewController:peoplePicker animated:YES completion:nil];
  77. }
  78. #pragma mark -
  79. #pragma mark ABPeoplePickerNavigationController 委托方法实现
  80. //点击Cancel按钮时调用
  81. - (void)peoplePickerNavigationControllerDidCancel:(ABPeoplePickerNavigationController *)peoplePicker
  82. {
  83. [peoplePicker dismissViewControllerAnimated:YES completion:nil];
  84. }
  85. //选择联系人时调用
  86. - (void)peoplePickerNavigationController:(ABPeoplePickerNavigationController*)peoplePicker didSelectPerson:(ABRecordRef)person {
  87. //获取选择联系人的姓名
  88. NSString *name = CFBridgingRelease(ABRecordCopyCompositeName(person));
  89. //将姓名添加到self.contactNames数组
  90. [self.contactNames addObject:name];
  91. //获取ID,将ID添加到self.contactIDs数组
  92. [self.contactIDs addObject:[NSNumber numberWithInt:ABRecordGetRecordID(person)]];
  93. //peoplePicker界面退回
  94. [peoplePicker dismissViewControllerAnimated:YES completion:nil];
  95. //取得最后一个放入contactIDs中的ID,也就是刚刚选择的ID
  96. NSIndexPath *path = [NSIndexPath indexPathForRow:self.contactIDs.count-1 inSection:0];
  97. //选中联系人插入到首页表视图中
  98. NSArray *arry = [NSArray arrayWithObject:path];
  99. [self.tableView insertRowsAtIndexPaths:arry withRowAnimation:UITableViewRowAnimationRight];
  100. }
  101. #pragma mark -
  102. #pragma mark ABPersonViewController 委托方法实现
  103. - (BOOL)personViewController:(ABPersonViewController *)personViewController
  104. shouldPerformDefaultActionForPerson:(ABRecordRef)person
  105. property:(ABPropertyID)property identifier:(ABMultiValueIdentifier)identifierForValue
  106. {
  107. return YES;
  108. }
  109. #pragma mark -
  110. #pragma mark ABNewPersonViewController 委托方法实现
  111. - (void)newPersonViewController:(ABNewPersonViewController *)newPersonView
  112. didCompleteWithNewPerson:(ABRecordRef)person
  113. {
  114. NSString *name = CFBridgingRelease(ABRecordCopyCompositeName(person));
  115. [self.contactNames addObject:name];
  116. [self.contactIDs addObject:[NSNumber numberWithInt:ABRecordGetRecordID(person)]];
  117. [newPersonView dismissViewControllerAnimated:YES completion:nil];
  118. //取得最后一个放入contactIDs中的ID,也就是刚刚选择的ID
  119. NSIndexPath *path = [NSIndexPath indexPathForRow:self.contactIDs.count-1 inSection:0];
  120. //选中联系人插入到首页表视图中
  121. NSArray *arry = [NSArray arrayWithObject:path];
  122. [self.tableView insertRowsAtIndexPaths:arry withRowAnimation:UITableViewRowAnimationRight];
  123. }
  124. @end
隐藏

2 平衡球

2.1 问题

IOS可以通过内置的加速计知道用户握持设备的方式,以及用户是否移动了设备,Core Motion框架提供设备移动的所有值。本案例使用Core Motion框架完成一个平衡球的小游戏,用户移动设备小球会根据用户移动的方向滚动,用户保持小球滚动到终点而不碰撞到墙壁,如图-8所示:

图-8

2.2 方案

首先创建一个SingleViewApplication应用,在Storyboard文件中搭建界面,本案例中的场景中使用带有背景颜色的ImageView控件当做隔墙,然后左上角摆放一个小球,同样是ImageView控件。将所有隔墙关联成ViewController的IBOutletCollection属性walls,将小球关联成ViewController的IBOutlet属性ball。

其次在ViewController类扩展中定义两个私有属性CMMotionManager类型的motionManager和NSOperationQueue类型的queue。在viewDidLoad方法中对这两个属性进行初始化,motionManager将观察动作事件,它需要创建一个队列用做完成工作的容器。

接下来配置加速器,首先确保设备确实拥有加速器,然后设置更新频率为1/15s,最后使用startAccelerometerUpdatesToQueue:withHandler:方法告诉motionManager开始报告加速计更新,传入队列和代码块,队列中放置着每次发生更新时要完成的工作,代码块定义这些工作。

最后完成代码块中的代码,本案例中代码块中需要根据每次更新的数据计算出小球滚动的距离和方向,并且需要判断小球是否碰到墙壁,碰到墙壁则游戏结束重新开始,未碰撞到任何墙壁顺利到达终点则游戏成功。

2.3 步骤

实现此案例需要按照如下步骤进行。

步骤一:搭建界面

首先创建一个SingleViewApplication应用,在Storyboard文件中搭建界面,本案例中的场景中使用带有背景颜色的ImageView控件当做隔墙,然后左上角摆放一个小球,同样是ImageView控件。将所有隔墙关联成ViewController的IBOutletCollection属性walls,将小球关联成ViewController的IBOutlet属性ball,代码如下所示:

  1. @interface ViewController ()
  2. //终点位置
  3. @property (weak, nonatomic) IBOutlet UIImageView *green;
  4. @property (weak, nonatomic) IBOutlet UIImageView *red;
  5. @property (strong, nonatomic) IBOutletCollection(UIImageView) NSArray *walls;
  6. @property (weak, nonatomic) IBOutlet UIButton *ball;
  7. @end

在Storyboard中完成的界面如图-9所示:

图-9

步骤二:创建动作管理器

在ViewController类扩展中定义两个私有属性CMMotionManager类型的motionManager和NSOperationQueue类型的queue。在viewDidLoad方法中对这两个属性进行初始化,motionManager将观察动作事件,它需要创建一个队列用做完成工作的容器,代码如下所示:

  1. @property (nonatomic,strong) CMMotionManager *motionManager;
  2. @property (nonatomic,strong) NSOperationQueue *queue;

接下来配置加速器,首先确保设备确实拥有加速器,然后设置更新频率为1/15s,最后使用startAccelerometerUpdatesToQueue:withHandler:方法告诉motionManager开始报告加速计更新,传入队列和代码块,队列中放置着每次发生更新时要完成的工作,代码块定义这些工作,代码如下所示:

  1. - (void)viewDidLoad {
  2. [super viewDidLoad];
  3. self.motionManager = [[CMMotionManager alloc]init];
  4. self.queue = [[NSOperationQueue alloc]init];
  5. if (self.motionManager.accelerometerAvailable) {
  6. self.motionManager.accelerometerUpdateInterval = 1.0/15;
  7. [self.motionManager startAccelerometerUpdatesToQueue:self.queue withHandler:^(CMAccelerometerData *accelerometerData, NSError *error) {
  8. }];
  9. }
  10. }

步骤三:实现小球滚动功能

在代码块中实现小球滚动功能,需要根据每次更新的accelerometerData.acceleration数据计算出小球滚动的距离和方向,然后回到主线程更新界面,需要判断小球是否碰到墙壁,碰到墙壁则游戏结束重新开始,未碰撞到任何墙壁顺利到达终点则游戏成功,代码如下所示:

  1. - (void)viewDidLoad {
  2. [super viewDidLoad];
  3. self.motionManager = [[CMMotionManager alloc]init];
  4. self.queue = [[NSOperationQueue alloc]init];
  5. if (self.motionManager.accelerometerAvailable) {
  6. self.motionManager.accelerometerUpdateInterval = 1.0/15;
  7. // [self.motionManager startAccelerometerUpdates];
  8. [self.motionManager startAccelerometerUpdatesToQueue:self.queue withHandler:^(CMAccelerometerData *accelerometerData, NSError *error) {
  9. //计算小球滚动的距离
  10. float x = oldx+.2*accelerometerData.acceleration.x;
  11. float y = oldy+.2*accelerometerData.acceleration.y;
  12. NSLog(@"%f,%f",accelerometerData.acceleration.x,accelerometerData.acceleration.y);
  13. NSArray *array = @[@(x),@(y)];
  14. //回到主线程更新界面
  15. [self performSelectorOnMainThread:@selector(moveBall:) withObject:array waitUntilDone:NO];
  16. }];
  17. }
  18. //记录小球最开始的中心点,游戏重新开始将回到该位置
  19. p = self.ball.center;
  20. //屏幕尺寸
  21. scrennSize = [UIScreen mainScreen].bounds.size;
  22. }
  23. -(void)moveBall:(NSArray*)array {
  24. float x = [array[0] floatValue];
  25. float y = [array[1] floatValue];
  26. self.ball.center = CGPointMake(self.ball.center.x+x,self.ball.center.y-y);
  27. oldx = x;
  28. oldy = y;
  29. //判断小球是否碰撞到屏幕两边需要改变方向
  30. if (self.ball.frame.origin.x<=0) {
  31. self.ball.frame = CGRectMake(0, self.ball.frame.origin.y, self.ball.frame.size.width, self.ball.frame.size.height);
  32. oldx = -oldx*.1;
  33. }else if (self.ball.frame.origin.x>=(scrennSize.width-self.ball.frame.size.width)) {
  34. self.ball.frame = CGRectMake((scrennSize.width-self.ball.frame.size.width), self.ball.frame.origin.y, self.ball.frame.size.width, self.ball.frame.size.height);
  35. oldx = -oldx*.1;
  36. }
  37. if (self.ball.frame.origin.y<=0) {
  38. self.ball.frame = CGRectMake(self.ball.frame.origin.x, 0, self.ball.frame.size.width, self.ball.frame.size.height);
  39. oldy = -oldy*.1;
  40. }else if (self.ball.frame.origin.y>=(scrennSize.height-self.ball.frame.size.height)) {
  41. self.ball.frame = CGRectMake(self.ball.frame.origin.x,(scrennSize.height-self.ball.frame.size.height), self.ball.frame.size.width, self.ball.frame.size.height);
  42. oldy = -oldy*.1;
  43. }
  44. //判断是否与墙壁有碰撞
  45. for (UIImageView *wall in self.walls) {
  46. if (CGRectIntersectsRect(self.ball.frame, wall.frame)) {
  47. UIAlertView *av = [[UIAlertView alloc]initWithTitle:@"提示" message:@"Game Over" delegate:self cancelButtonTitle:@"确定" otherButtonTitles:@"重新开始", nil];
  48. [av show];
  49. self.ball.center = p;
  50. return;
  51. }
  52. }
  53. if (CGRectIntersectsRect(self.ball.frame, self.green.frame)) {
  54. UIAlertView *av = [[UIAlertView alloc]initWithTitle:@"提示" message:@"Successful" delegate:nil cancelButtonTitle:@"确定" otherButtonTitles:@"重新开始", nil];
  55. [av show];
  56. return;
  57. }else if (CGRectIntersectsRect(self.ball.frame, self.red.frame)) {
  58. UIAlertView *av = [[UIAlertView alloc]initWithTitle:@"提示" message:@"fair" delegate:nil cancelButtonTitle:@"确定" otherButtonTitles:@"重新开始", nil];
  59. [av show];
  60. return;
  61. }
  62. }
  63. -(void)alertView:(UIAlertView *)alertView clickedButtonAtIndex:(NSInteger)buttonIndex {
  64. if (buttonIndex==1) {
  65. self.ball.center = p;
  66. }
  67. }

最后不要忘记放置手机屏幕旋转和隐藏状态栏,代码如下所示:

  1. -(NSUInteger)supportedInterfaceOrientations {
  2. r%turn UIInterfaceOrientationMaskPortrait;
  3. }
  4. -(BOOL)prdfersStatuSBarHidden { return YES;
  5. }

完成效果如图-10,图-11所示:

图 10

图-11

2.4 完整代码

本案例中,ViewController.m文件中的完整代码如下所示:

#import "ViewController.h"
#import <CoreMotion/CoreMotion.h>

@interface ViewController (){
    CGPoint p;
    float oldx;
    float oldy;
    CGSize scrennSize;
}
@property (nonatomic,strong) CMMotionManager *motionManager;
@property (nonatomic,strong) NSOperationQueue *queue;

@property (weak, nonatomic) IBOutlet UIImageView *green;
@property (weak, nonatomic) IBOutlet UIImageView *red;
@property (strong, nonatomic) IBOutletCollection(UIImageView) NSArray *walls;
@property (weak, nonatomic) IBOutlet UIButton *ball;
@end

@implementation ViewController

- (void)viewDidLoad {
    [super viewDidLoad];
    self.motionManager = [[CMMotionManager alloc]init];
    self.queue = [[NSOperationQueue alloc]init];
    if (self.motionManager.accelerometerAvailable) {
        self.motionManager.accelerometerUpdateInterval = 1.0/15;
        //        [self.motionManager startAccelerometerUpdates];
        [self.motionManager startAccelerometerUpdatesToQueue:self.queue withHandler:^(CMAccelerometerData *accelerometerData, NSError *error) {
            //计算小球滚动的距离
            float x = oldx+.2*accelerometerData.acceleration.x;
            float y = oldy+.2*accelerometerData.acceleration.y;
            NSLog(@"%f,%f",accelerometerData.acceleration.x,accelerometerData.acceleration.y);
            NSArray *array = @[@(x),@(y)];
            //回到主线程更新界面
            [self performSelectorOnMainThread:@selector(moveBall:) withObject:array waitUntilDone:NO];

        }];
    }
    //记录小球最开始的中心点,游戏重新开始将回到该位置
    p = self.ball.center;
    //屏幕尺寸
    scrennSize = [UIScreen mainScreen].bounds.size;
}
-(void)moveBall:(NSArray*)array {
    float x = [array[0] floatValue];
    float y = [array[1] floatValue];
    self.ball.center = CGPointMake(self.ball.center.x+x,self.ball.center.y-y);
    oldx = x;
    oldy = y;
    //判断小球是否碰撞到屏幕两边需要改变方向
    if (self.ball.frame.origin.x<=0) {
        self.ball.frame = CGRectMake(0, self.ball.frame.origin.y, self.ball.frame.size.width, self.ball.frame.size.height);
        oldx = -oldx*.1;
    }else if (self.ball.frame.origin.x>=(scrennSize.width-self.ball.frame.size.width)) {
        self.ball.frame = CGRectMake((scrennSize.width-self.ball.frame.size.width), self.ball.frame.origin.y, self.ball.frame.size.width, self.ball.frame.size.height);
        oldx = -oldx*.1;
    }
    if (self.ball.frame.origin.y<=0) {
        self.ball.frame = CGRectMake(self.ball.frame.origin.x, 0, self.ball.frame.size.width, self.ball.frame.size.height);
        oldy = -oldy*.1;
    }else if (self.ball.frame.origin.y>=(scrennSize.height-self.ball.frame.size.height)) {
        self.ball.frame = CGRectMake(self.ball.frame.origin.x,(scrennSize.height-self.ball.frame.size.height), self.ball.frame.size.width, self.ball.frame.size.height);
        oldy = -oldy*.1;
    }
    //判断是否与墙壁有碰撞
    for (UIImageView *wall in self.walls) {
        if (CGRectIntersectsRect(self.ball.frame, wall.frame)) {
            UIAlertView *av = [[UIAlertView alloc]initWithTitle:@"提示" message:@"Game Over" delegate:self cancelButtonTitle:@"确定" otherButtonTitles:@"重新开始", nil];
            [av show];
            self.ball.center = p;
            return;
        }
    }
    if (CGRectIntersectsRect(self.ball.frame, self.green.frame)) {
        UIAlertView *av = [[UIAlertView alloc]initWithTitle:@"提示" message:@"Successful" delegate:nil cancelButtonTitle:@"确定" otherButtonTitles:@"重新开始", nil];
        [av show];
        return;
    }else if (CGRectIntersectsRect(self.ball.frame, self.red.frame)) {
        UIAlertView *av = [[UIAlertView alloc]initWithTitle:@"提示" message:@"fair" delegate:nil cancelButtonTitle:@"确定" otherButtonTitles:@"重新开始", nil];
        [av show];
        return;
    }
}

-(void)alertView:(UIAlertView *)alertView clickedButtonAtIndex:(NSInteger)buttonIndex {
    if (buttonIndex==1) {
        self.ball.center = p;
    }
}

-(NSUInteger)supportedInterfaceOrientations {
    return UIInterfaceOrientationMaskPortrait;
}

-(BOOL)prefersStatusBarHidden {
    return YES;
}
@end
时间: 2024-10-12 15:30:24

通讯录 、 传感器的相关文章

传感器到底需要什么样的电路板

传感器,英文名称transducer,是一种检测装置,能感受到被测量的信息,并能将感受到的信息,按一定规律变换成为电信号或其他所需形式的信息输出,以满足信息的传输.处理.存储.显示.记录和控制等要求. 按照制造工艺来分类的话: 集成传感器是用标准的生产硅基半导体集成电路的工艺技术制造的.通常还将用于初步处理被测信号的部分电路也集成在同一芯片上,例如现在大力发展的MEMS传感器. 薄膜传感器则是通过沉积在介质衬底(基板)上的,相应敏感材料的薄膜形成的.使用混合工艺时,同样可将部分电路制造在此基板上

进阶篇-安卓系统:4.安卓手机动作传感器

动作传感器对于监测设备的移动非常有用,例如:倾斜.震动.旋转和摆动都属于动作传感器的监测范围.设备的移动通常是对用户输入的直接反应. 所有动作传感器都会返回三个浮点数的值,对于不同的传感器,这三个值的意义不同.例如,对于加速度传感器,会返回三个坐标轴的加速数据.对于陀螺仪传感器,会返回三个坐标周的旋转角速度. 动作传感器的使用与数据返回:加速度传感器 如果单纯的使用加速度传感器传回的数据,会发现Z轴的的加速度是9.8多.所以看来安卓是把静止的手机竖直加速度默认为重力加速度,并且XY轴的数据也不是

Android12_播放器_surfaceVIew_照相机_传感器

编程的时间与空间的概念,两者不可兼得(技术固定),时间换空间,空间换时间 sufaceView占用比较大的空间但是效率高 1,音乐播放器 MediaPlayer ①同步的 大致流程按下图走即可,播放最好写在服务里,因为要在后台播放 1.1 new出来的mediaplayer 默认处于Idie(空闲),reset()也可以让其处于初始状态 1.2 setDataSource()设置好文件之后就处于Initialized()初始化状态 1.3 可以通过setOnErrorListener方法查看播放

传感器网络的路由

1.传感器网络的路由特点 传感器网络作为一种自组织的动态网络,当节点失效.新节点加入导致网络拓扑结构动态变化时需要网络能够自动愈合.传感器网络中路由的关键技术就是多跳自组织的网络路由协议,另外传感器网络中的路由机制还需要与数据融合技术联系在一起.根据不同的传感器网络应用,一共有四种思想的路由协议.能量感知路由是高效利用网络能量的路由协议,它侧重点是最少能量消耗和最长网络生存期等问题:基于查询的路由比较适合环境检测方面的应用,在这类应用中需要不断地的查询传感器节点采集的数据,通信流量集中在汇聚节点

Android基础入门教程——10.12 传感器专题(3)——加速度-陀螺仪传感器

Android基础入门教程--10.12 传感器专题(3)--加速度/陀螺仪传感器 标签(空格分隔): Android基础入门教程 本节引言: 本节继续来扣Android中的传感器,本节带来的是加速度传感器(Accelerometer sensor)以及 陀螺仪传感器(Gyroscope sensor),和上一节的方向传感器一样有着x,y,z 三个轴, 还是要说一点:x,y轴的坐标要和绘图那里的x,y轴区分开来!传感器的是以左下角 为原点的!x向右,y向上!好的,带着我们的套路来学本节的传感器吧

ios-私人通讯录 页面间的跳转和传值

这个demo 有多个页面 并涉及顺传和逆传 而且还有一个第三方库的导入 来实现自定义提示消息的特效 利用代理来实现页面间的传值 一个页面代表一个controller 这次  ViewController  反而一句代码都没写 // // HMContact.h // 私人通讯录 // // Created by YaguangZhu on 15/9/6. // Copyright (c) 2015年 YaguangZhu. All rights reserved. // #import <Fou

ObjectC----实现简单的通讯录(增删改查)

// Created By 郭仔 2015年04月09日21:27:50 经过两天的低迷,状态在慢慢的回归了,生活还要继续,人生还需奋斗! 祝:好人一生平安!!! ======================================================================== 题目描述: 1.创建AddressBook类. 1)使?用字典作为容器,字典的Key值为分组名(姓名?首字?母,?大写),value值为数组,数组 中存放联系?人(Person实例).(5分

C语言写郑州大学校友通讯录

1 #include <stdio.h> 2 #include <string.h> 3 #include <stdlib.h> 4 #define LEN sizeof(struct address_list) 5 6 /* 7 *************************通讯录结构体*********************************** 8 */ 9 10 struct address_list 11 { 12 char name[30]; /

Android操作系统11种传感器介绍

#define SENSOR_TYPE_ACCELEROMETER 1 //加速度 #define SENSOR_TYPE_MAGNETIC_FIELD 2 //磁力 #define SENSOR_TYPE_ORIENTATION 3 //方向 #define SENSOR_TYPE_GYROSCOPE 4 //陀螺仪 #define SENSOR_TYPE_LIGHT 5 //光线感应 #define SENSOR_TYPE_PRESSURE 6 //压力 #define SENSOR_TYP