前言
对于应用的交互,重力感应的加速器和陀螺仪可以开创一些比较新颖的交互方式,比如使用加速器实现摇一摇功能,使用陀螺仪实现图片跟随设备旋转或者是敲击反应(实现pop back效果)等等;
(一)利用cmmotionmanager获取设备的及速度实现摇一摇的功能,再配合上自己设计的业务逻辑,就可以现实市面上很多应用的摇一摇功能了。
#import "MotionViewController.h"
#import <CoreMotion/CoreMotion.h>
#import "FloatTextField.h"
static const double accelerationThreshold = 2.0f;
@interface MotionViewController ()
@property CMMotionManager *motionManager;
@property NSOperationQueue *operationQueue;
@property (nonatomic, strong) UIImageView *image;
@end
@implementation MotionViewController
- (void)viewDidLoad {
[super viewDidLoad];
self.view.backgroundColor = [UIColor whiteColor];
_operationQueue = [[NSOperationQueue alloc] init];
_motionManager = [CMMotionManager new];
_motionManager.accelerometerUpdateInterval = 1.0f / 60;
_image = [[UIImageView alloc] initWithFrame:CGRectMake(0, 0, 100, 100)];
_image.center = self.view.center;
_image.backgroundColor = [UIColor blueColor];
[self.view addSubview:_image];
FloatTextField *textfield = [[FloatTextField alloc] initWithFrame:CGRectMake(0, 100, 200, 40)];
textfield.backgroundColor = [UIColor lightGrayColor];
[self.view addSubview:textfield];
}
- (void)viewDidAppear:(BOOL)animated {
[super viewDidAppear:animated];
[self startAccelermeter];
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(receiveNotification:) name:UIApplicationDidEnterBackgroundNotification object:nil];
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(receiveNotification:) name:UIApplicationWillEnterForegroundNotification object:nil];
}
- (void)receiveNotification:(NSNotification *)notification {
if ([notification.name isEqualToString:UIApplicationDidEnterBackgroundNotification]) {
[_motionManager stopAccelerometerUpdates];
} else {
[self startAccelermeter];
}
}
- (void)startAccelermeter {
[_motionManager startAccelerometerUpdatesToQueue:_operationQueue withHandler:^(CMAccelerometerData * _Nullable accelerometerData, NSError * _Nullable error) {
[self outputaccelerometerData:accelerometerData.acceleration];
}];
}
- (void)outputaccelerometerData:(CMAcceleration)acceleration {
double accelermeter = sqrt(pow(acceleration.x, 2) + pow(acceleration.y, 2) + pow(acceleration.z, 2));
if (accelermeter > accelerationThreshold) {
[_motionManager stopAccelerometerUpdates];
[_operationQueue cancelAllOperations];
[[NSOperationQueue mainQueue] addOperationWithBlock:^{
[self turnRight];
}];
}
}
-(void)setAnchorPoint:(CGPoint)anchorPoint forView:(UIView *)view
{
CGPoint newPoint = CGPointMake(view.bounds.size.width * anchorPoint.x,
view.bounds.size.height * anchorPoint.y);
CGPoint oldPoint = CGPointMake(view.bounds.size.width * view.layer.anchorPoint.x,
view.bounds.size.height * view.layer.anchorPoint.y);
newPoint = CGPointApplyAffineTransform(newPoint, view.transform);
oldPoint = CGPointApplyAffineTransform(oldPoint, view.transform);
CGPoint position = view.layer.position;
position.x -= oldPoint.x;
position.x += newPoint.x;
position.y -= oldPoint.y;
position.y += newPoint.y;
view.layer.position = position;
view.layer.anchorPoint = anchorPoint;
}
- (void)turnRight {
CABasicAnimation *rotate = [CABasicAnimation animationWithKeyPath:@"transform.rotation"];
rotate.fromValue = [NSNumber numberWithFloat:0];
rotate.toValue = [NSNumber numberWithFloat:M_PI / 3.0];
rotate.duration = 0.18;
rotate.repeatCount = 2;
rotate.autoreverses = YES;
[CATransaction begin];
[self setAnchorPoint:CGPointMake(-0.2, 0.9) forView:_image];
[CATransaction setCompletionBlock:^{
[self getData];
}];
[_image.layer addAnimation:rotate forKey:nil];
[CATransaction commit];
}
- (void)getData {
[self startAccelermeter];
}
@end
解释一下-(void)setAnchorPoint:(CGPoint)anchorPoint forView:(UIView *)view函数,此函数是通过设置的anchorPoint,计算出对应的position,达到不移动的效果。此方法参考至这篇文章。
总结
以上只是实现了摇一摇的功能,一个简单的效果,其他的更好更复杂功能,大家可以去实践,通过cmmotionmanager获取得到数据,然后通过数据的计算,实现你想要的效果。