先來(lái)看一下效果

111.gif
這是通過(guò)調(diào)用iOS的陀螺儀和加速度計(jì)。通過(guò)傾斜手機(jī)實(shí)現(xiàn)的效果
Core Motion
加速度計(jì)和陀螺儀是通過(guò)Core Motion框架,來(lái)管理訪問(wèn)的。此框架提供了CMMotionManager類,它提供的數(shù)據(jù)都是用來(lái)描述設(shè)備的移動(dòng)的。還提供了CMAccelerometerData和CMGroData,他們可以訪問(wèn)原生的加速度計(jì)和陀螺儀信息。另外還有CMDeviceMotion,這個(gè)類里面包含有加速度計(jì)和陀螺儀的測(cè)量數(shù)據(jù),以及方位信息。即設(shè)備是平放,朝上,朝下,還是朝左等信息。話不多說(shuō)還是直接上代碼。
先來(lái)個(gè)坐標(biāo)系作為參考

屏幕快照 2016-07-09 下午5.24.42.png
看一下各項(xiàng)數(shù)據(jù)
#define kUpdateInterval (1.f / 60.f)//定義一個(gè)更新時(shí)間
@property (nonatomic,strong)CMMotionManager *motionManager;
@property (nonatomic,strong)NSOperationQueue *quene;
//聲明一個(gè)線程
self.motionManager = [[CMMotionManager alloc]init];
NSOperationQueue *quene = [[NSOperationQueue alloc]init];
初始化一個(gè)線程,動(dòng)作管理器需要一個(gè)單獨(dú)的線程來(lái)運(yùn)行,以便在每次發(fā)生事件時(shí)放入要執(zhí)行的工作。蘋果文檔之處不要放在默認(rèn)隊(duì)列,可能會(huì)被事件填滿,無(wú)法處理別的事件
if (self.motionManager.deviceMotionAvailable) {
self.motionManager.deviceMotionUpdateInterval = 0.1;
//設(shè)置更新數(shù)據(jù)的時(shí)間間隔
[self.motionManager startDeviceMotionUpdatesToQueue: quene withHandler:^(CMDeviceMotion * _Nullable motion, NSError * _Nullable error) {
CMRotationRate rotationRate = motion.rotationRate;
//旋轉(zhuǎn)速率對(duì)應(yīng)x,y,z分別是設(shè)備繞x,y,z 軸(上面有圖參考)
的旋轉(zhuǎn)速率,順時(shí)針為正,逆時(shí)針為負(fù)
CMAcceleration gravity = motion.gravity;
//自然加速度,可是識(shí)別手機(jī)的放置方向,設(shè)備平放在桌上,z=-1;
屏幕朝左側(cè)立,x = -1;充電口朝下垂直放置,y=-1
CMAcceleration userAcc = motion.userAcceleration;
//用戶運(yùn)動(dòng)手機(jī)造成的加速度,分別向xyz方向運(yùn)動(dòng)時(shí),正向時(shí)即為正值
CMAttitude *attitude = motion.attitude;
//設(shè)備的旋轉(zhuǎn)程度,也可以理解為設(shè)備繞xyz軸旋轉(zhuǎn)的程度,單位是
弧度,即旋轉(zhuǎn)一周的值為2π,手機(jī)繞舉個(gè)例子:把手機(jī)平放在桌面上,
旋轉(zhuǎn)手機(jī)Yaw(偏移)開(kāi)始變化,旋轉(zhuǎn)180°時(shí)yaw = 3.14;
繞Y軸旋轉(zhuǎn)時(shí)Roll變化;繞X軸旋轉(zhuǎn)時(shí)Pitch變化(方向不在多做討論,參考系不一樣,沒(méi)法統(tǒng)一)
NSString *gyroscopeText = [NSString stringWithFormat:@"Rotation:\\n x = %.2f\\n y = %.2f\\n
z = %.2f",rotationRate.x,rotationRate.y,rotationRate.z];
NSString *acceleratiorText = [NSString stringWithFormat:@"Accelertion: \\n Gravity x = %.2f\\tUser x = %.2f
\\n Gravity y = %.2f\\tUser y = %.2f \\n Gravity z = %.2f\\tUser z = %.2f \\n",gravity.x,userAcc.x,gravity.y,userAcc.y,gravity.z,userAcc.z];
NSString *attitudeText = [NSString stringWithFormat:@"Attitute:\\n Roll = %.2f\\nPitch = %.2f
\\nYaw = %.2f\\n",attitude.roll,attitude.pitch,attitude.yaw];
// NSLog(@"%@",gyroscopeText);
dispatch_async(dispatch_get_main_queue(), ^{
_gyroscopeLabel.text = gyroscopeText;
_accelerometerLabel.text = acceleratiorText;
_attitudeLabel.text = attitudeText;
});
}];
}
然后我們來(lái)做一個(gè)Demo
controller中代碼實(shí)現(xiàn)
#define kUpdateInterval (1.f / 60.f)//更新頻率高一點(diǎn)
@interface BallViewController ()
@property (nonatomic,strong)CMMotionManager *motionManager;
@property (nonatomic,strong)NSOperationQueue *quene;
@end
- (void)viewDidLoad {
[super viewDidLoad];
BallView *ballView = [[BallView alloc]initWithFrame:self.view.bounds];
//自己寫的類繼承自UIView
[self.view addSubview:ballView];
self.motionManager = [[CMMotionManager alloc]init];
self.quene = [[NSOperationQueue alloc]init];
self.motionManager.deviceMotionUpdateInterval = kUpdateInterval;
[self.motionManager startDeviceMotionUpdatesToQueue:_quene withHandler:^(CMDeviceMotion * _Nullable motion, NSError * _Nullable error) {
//此處也可以傳入motion.userAcceleration。(用戶移動(dòng)手機(jī)產(chǎn)生的加速度)這樣就可以實(shí)現(xiàn)搖動(dòng)來(lái)控制(ballView里面的放大倍數(shù)記得要改大一點(diǎn))
[ballView setAcceleration:motion.gravity];
dispatch_async(dispatch_get_main_queue(), ^{
[ballView update];
//主線程更新UI
});
}];
}
BallView的實(shí)現(xiàn)
.h文件
#import <UIKit/UIKit.h>
#import <CoreMotion/CoreMotion.h>
@interface BallView : UIView
@property (nonatomic,assign)CMAcceleration acceleration;
- (void)update;
@end
.m文件
@interface BallView ()
@property (nonatomic,assign)CGFloat width;
@property (nonatomic,assign)CGFloat height;
@property (nonatomic,assign)CGFloat imageWidth;
@property (nonatomic,assign)CGFloat imageHeight;
@property (nonatomic,strong)UIImage *image;
@property (nonatomic,strong)UIImageView *imageView;
@property (nonatomic,assign)CGPoint currentPoint;//當(dāng)前ImageView位置
@property (nonatomic,assign)CGFloat ballXVelocity;//X方向速度
@property (nonatomic,assign)CGFloat ballYVelocity;//Y方向速度
@end
@implementation BallView
- (instancetype)initWithFrame:(CGRect)frame{
self = [super initWithFrame:frame];
if (self) {
[self commoninit];
self.backgroundColor = [UIColor whiteColor];
}
return self;
}
- (void)commoninit{
self.image = [UIImage imageNamed:@"btn_nav04@3x"];
self.imageView = [[UIImageView alloc]initWithFrame:CGRectMake(0, 0, self.imageWidth, self.imageHeight)];
self.imageView.image = _image;
[self addSubview:self.imageView];
self.currentPoint = CGPointMake(self.bounds.size.width/2.f+self.image.size.width/2.f, self.bounds.size.height/2.f+self.image.size.height/2.f);
self.imageView.center = _currentPoint;
}
- (void)setCurrentPoint:(CGPoint)newPoint{
_currentPoint = newPoint;
//邊緣判斷
if (self.currentPoint.x <= self.imageWidth/2.f) {
_currentPoint.x = self.imageWidth/2.f;
self.ballXVelocity = -_ballXVelocity/2.f;
//反彈效果,接觸邊緣后加速度反向減半
}
if (self.currentPoint.y <= self.imageHeight/2.f) {
_currentPoint.y = self.imageHeight/2.f;
self.ballYVelocity = -_ballYVelocity/2.f;
//反彈效果,接觸邊緣后加速度反向減半
}
if (self.currentPoint.x >= self.width -self.imageWidth/2.f ) {
_currentPoint.x = self.width -self.imageWidth/2.f;
self.ballXVelocity = -_ballXVelocity/2.f;
//反彈效果,接觸邊緣后加速度反向減半
}
if (self.currentPoint.y >= self.height -self.imageHeight/2.f ) {
_currentPoint.y = self.height -self.imageHeight/2.f;
self.ballYVelocity = -_ballYVelocity/2.f;
//反彈效果,接觸邊緣后加速度反向減半
}
[self updateCenter];
}
- (void)updateCenter{
self.imageView.center = _currentPoint;
}
- (void)update{
static NSDate *lastUpdateTime = nil;
if (lastUpdateTime != nil) {
NSTimeInterval secondsSinceLastDraw = [[NSDate date] timeIntervalSinceDate:lastUpdateTime];//兩次更新的時(shí)間差
self.ballXVelocity = self.ballXVelocity + (self.acceleration.x * secondsSinceLastDraw);
//X方向上原速度加上加速度乘以時(shí)間,計(jì)算當(dāng)前速度
self.ballYVelocity = self.ballYVelocity - (self.acceleration.y * secondsSinceLastDraw);
//Y方向上原速度加上加速度乘以時(shí)間,計(jì)算當(dāng)前速度
CGFloat xAccel = secondsSinceLastDraw * self.ballXVelocity * 1000;
//計(jì)算位置變化量。由于這個(gè)值很小,所以我們要放大一些才更加真實(shí)此處
//若想使用搖動(dòng),要把放大倍數(shù)調(diào)大,10000效果不錯(cuò)
CGFloat yAccel = secondsSinceLastDraw * self.ballYVelocity * 1000;
self.currentPoint = CGPointMake(self.currentPoint.x + xAccel, self.currentPoint.y + yAccel);
}
lastUpdateTime = [NSDate date];
}
#pragma mark - widthAndHeight
- (CGFloat)width{
return self.bounds.size.width;
}
- (CGFloat)height{
return self.bounds.size.height;
}
- (CGFloat)imageWidth{
return self.image.size.width;
}
- (CGFloat)imageHeight{
return self.image.size.height;
}
這樣你就可以實(shí)現(xiàn),傾斜手機(jī)來(lái)移動(dòng)圖片,就像真是的重力產(chǎn)生的效果一樣。同樣也可以實(shí)現(xiàn),搖動(dòng)的效果。(就像安卓的360原來(lái)的版本有個(gè)搖動(dòng)的球清理內(nèi)存那樣的效果)。
如需轉(zhuǎn)載請(qǐng)注明出處,請(qǐng)尊重作者的勞動(dòng)成果。