我正在使用CMMotionManager在我的视图上移动按钮,图像等,因为设备向前,向后,向右,向左倾斜。我得到姿态俯仰和滚动,然后使用这些来为表示屏幕上像素位置的字符串赋值。
以下是我获取信息的方式
motionManager = [[CMMotionManager alloc] init];
motionManager.deviceMotionUpdateInterval = 0.05f;
[motionManager startDeviceMotionUpdatesToQueue:[NSOperationQueue currentQueue] withHandler:^(CMDeviceMotion *motion, NSError *error) {
NSNumberFormatter *formatter = [[NSNumberFormatter alloc] init];
[formatter setNumberStyle:NSNumberFormatterDecimalStyle];
[formatter setMaximumFractionDigits:2];
[formatter setRoundingMode: NSNumberFormatterRoundUp];
numberString = [formatter stringFromNumber:[NSNumber numberWithFloat:motion.attitude.roll /8]];
numberString1 = [formatter stringFromNumber:[NSNumber numberWithFloat:motion.attitude.pitch /8]];
}];
这就是我分配它们的方式。
NSString *deltax = numberString;
NSString *deltay = numberString1;
NSLog(@"xString;%@",numberString);
if ([deltax isEqualToString:@"-0.01"]) {
xString = @"160";}
else if ([deltax isEqualToString:@"-0.02"]) {
xString = @"161";}
else if ([deltax isEqualToString:@"-0.03"]) {
xString = @"162";}
else if ([deltax isEqualToString:@"-0.04"]) {
xString = @"163";}
等
我已经制作了它们,因此x轴在屏幕上连续上下(来回)。即-.01与-.40,.01和.40相同。从-01和.01开始,它们的接近程度相同,值越大,从-40和4.4越小。我也对y轴做了同样的事情。 -.01和.01是284和-.20,.20是264.但是在这种情况下,数字从-01上升到.01。
这里有一些例子
//x axis
if ([deltax isEqualToString:@"-0.01"]) {
xString = @"160";}
else if ([deltax isEqualToString:@"-0.02"]) {
xString = @"161";}
else if ([deltax isEqualToString:@"-0.03"]) {
xString = @"162";}
else if ([deltax isEqualToString:@"-0.04"]) {
xString = @"163";}
else if ([deltax isEqualToString:@"-0.37"]) {
xString = @"156";}
else if ([deltax isEqualToString:@"-0.38"]) {
xString = @"157";}
else if ([deltax isEqualToString:@"-0.39"]) {
xString = @"158";}
else if ([deltax isEqualToString:@"-0.4"]) {
xString = @"159";}
else if ([deltax isEqualToString:@"0.01"]) {
xString = @"159";}
else if ([deltax isEqualToString:@"0.02"]) {
xString = @"158";}
else if ([deltax isEqualToString:@"0.03"]) {
xString = @"157"; }
else if ([deltax isEqualToString:@"0.04"]) {
xString = @"156";}
else if ([deltax isEqualToString:@"0.37"]) {
xString = @"163";}
else if ([deltax isEqualToString:@"0.38"]) {
xString = @"162";}
else if ([deltax isEqualToString:@"0.39"]) {
xString = @"161";}
else if ([deltax isEqualToString:@"0.4"]) {
xString = @"160";}
//y axis
if ([deltay isEqualToString:@"-0.01"]) {
yString = @"284";}
else if ([deltay isEqualToString:@"-0.02"]) {
yString = @"285";}
else if ([deltay isEqualToString:@"-0.03"]) {
yString = @"286";}
else if ([deltay isEqualToString:@"-0.04"]) {
yString = @"287";}
else if ([deltay isEqualToString:@"-0.17"]) {
yString = @"300"; }
else if ([deltay isEqualToString:@"-0.18"]) {
yString = @"301";}
else if ([deltay isEqualToString:@"-0.19"]) {
yString = @"302";}
else if ([deltay isEqualToString:@"-0.2"]) {
yString = @"303";}
else if ([deltay isEqualToString:@"0.01"]) {
yString = @"283";}
else if ([deltay isEqualToString:@"0.02"]) {
yString = @"282";}
else if ([deltay isEqualToString:@"0.03"]) {
yString = @"281";}
else if ([deltay isEqualToString:@"0.04"]) {
yString = @"280"; }
else if ([deltay isEqualToString:@"0.17"]) {
yString = @"267";}
else if ([deltay isEqualToString:@"0.18"]) {
yString = @"266";}
else if ([deltay isEqualToString:@"0.19"]) {
yString = @"265";}
else if ([deltay isEqualToString:@"0.2"]) {
yString = @"264";}
通过这种方式,从一个方向到下一个方向有连续的流动。
但是我遇到了一个小问题。当手机向前倾斜并从.2 faceUp方向转到.2 faceDown方向时。我得到一个生涩的动作。在faceUp .2按钮等突然向左移动,当它移动到faceDown .20时,它们向右移动。否则按钮等以.19和-19为中心并返回以正常操作(如预期的那样)。我试图调用DeviceOrientationFaceUp和FaceDown,但这似乎没有帮助。
是否有任何人有此行为的经验并知道修复或有任何建议。
我还添加了这个部分来上下左右移动按钮。无论手机的位置在哪里,都可以使用此方法上下左右按钮。
//used to assign numerical values
NSString *string2 = xString;
int n = [string2 intValue];
NSLog(@"n:%d",n);
NSString *string3 = xString1;
int p = [string3 intValue];
NSLog(@"p:%d",p);
NSString *string4 = yString;
int q = [string4 intValue];
NSLog(@"q:%d",q);
NSString *string5 = yString1;
int r = [string5 intValue];
NSLog(@"r:%d",r);
//used to move the buttons etc.
imageView2.center = CGPointMake(p, q);
imageView.center = CGPointMake(n -63, q);
imageframe.center = CGPointMake(n -63, q);
textView.center = CGPointMake(n -62, q - 184);
label1.center = CGPointMake(n + 97, q - 195 );
english.center = CGPointMake(n + 97, q - 159);
这是一种视差运动的东西。
答案 0 :(得分:4)
一些反应:
我可能会建议使用gravity
而不是attitude
,因为它很好地代表了设备的物理方向。
我可能只是更新数值,而不是使用字符串来保存值。
而不是所有这些if
语句,只需要一个表示视图应如何放置的公式。
如果你想移动一堆视图,你应该将它们放在UIView
(通常称为“容器视图”中,不要与IB中的自定义容器控件混淆名称),然后只需移动容器视图。
因此,如果使用autolayout,我可能会有以下属性:
@property (nonatomic, strong) CMMotionManager *motionManager;
@property CGFloat top;
@property CGFloat left;
然后我可以像这样更新自动布局约束:
self.motionManager = [[CMMotionManager alloc] init];
self.motionManager.deviceMotionUpdateInterval = 0.05f;
self.top = self.topConstraint.constant;
self.left = self.leadingConstraint.constant;
[self.motionManager startDeviceMotionUpdatesToQueue:[NSOperationQueue mainQueue] withHandler:^(CMDeviceMotion *motion, NSError *error) {
self.leadingConstraint.constant = self.left - motion.gravity.x / 8.0 * 100.0;
self.topConstraint.constant = self.top - motion.gravity.y / 8.0 * 100.0;
}];
或者如果不使用autolayout:
@property (nonatomic, strong) CMMotionManager *motionManager;
@property CGPoint originalCenter;
和
self.motionManager = [[CMMotionManager alloc] init];
self.motionManager.deviceMotionUpdateInterval = 0.05f;
self.originalCenter = self.containerView.center;
[self.motionManager startDeviceMotionUpdatesToQueue:[NSOperationQueue mainQueue] withHandler:^(CMDeviceMotion *motion, NSError *error) {
self.containerView.center = CGPointMake(self.originalCenter.x - motion.gravity.x / 8.0 * 100.0, self.originalCenter.y - motion.gravity.y / 8.0 * 100.0);
}];
坦率地说,让运动管理器在主队列中运行会给我带来意志,所以我可能(a)为运动更新创建一个NSOperationQueue
并且只更新一些类属性; (b)使用CADisplayLink
(QuartzCore.framework的一部分)更新视图(如果需要)。因此:
@property (nonatomic, strong) CMMotionManager *motionManager;
@property (nonatomic, strong) NSOperationQueue *motionQueue;
@property (nonatomic) CMAcceleration gravity;
@property (nonatomic) CGPoint originalCenter;
@property (nonatomic) BOOL updatePosition;
@property (nonatomic, strong) NSMutableArray *angles;
@property (nonatomic, strong) CADisplayLink *displayLink;
和
- (void)viewDidDisappear:(BOOL)animated
{
[self stopDisplayLink];
[self.motionManager stopDeviceMotionUpdates];
self.motionManager = nil;
self.motionQueue = nil;
}
- (void)viewDidAppear:(BOOL)animated
{
[super viewDidAppear:animated];
self.motionManager = [[CMMotionManager alloc] init];
self.motionManager.deviceMotionUpdateInterval = 0.05f;
self.motionQueue = [[NSOperationQueue alloc] init];
self.motionQueue.name = [[[NSBundle mainBundle] bundleIdentifier] stringByAppendingString:@".motion"];
self.originalCenter = self.containerView.center;
self.updatePosition = NO;
[self.motionManager startDeviceMotionUpdatesToQueue:self.motionQueue withHandler:^(CMDeviceMotion *motion, NSError *error) {
@synchronized(self) {
self.gravity = motion.gravity;
self.updatePosition = YES;
}
}];
[self startDisplayLink];
}
- (void)startDisplayLink
{
self.displayLink = [CADisplayLink displayLinkWithTarget:self selector:@selector(handleDisplayLink:)];
[self.displayLink addToRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode];
}
- (void)stopDisplayLink
{
[self.displayLink invalidate];
self.displayLink = nil;
}
- (void)handleDisplayLink:(CADisplayLink *)displayLink
{
@synchronized(self) {
if (!self.updatePosition)
return;
self.containerView.center = CGPointMake(self.originalCenter.x - self.gravity.x / 8.0 * 100.0, self.originalCenter.y - self.gravity.y / 8.0 * 100.0);
self.updatePosition = NO;
}
}
答案 1 :(得分:0)
我做了以下事情: 在可调窗口内采用最大值和最小值(闪烁噪声)并取平均值的数学运算。 没有更多的振荡!
这是我的代码,以避免在may app中闪烁:
float xAxis,yAxis, zAxis;
xAxis = self.manager.accelerometerData.acceleration.x;
yAxis = self.manager.accelerometerData.acceleration.y;
zAxis = self.manager.accelerometerData.acceleration.z;
// returns if the phone is lying on the table:
if (zAxis < -0.8 || zAxis > 0.8) return;
CGFloat angle = atan2f(xAxis, yAxis ); // The angle!!!
float noise = 0.011; // Flicker noise (the noise you want to filter)
// max and min are global variables
if (angle > max){
max = angle;
min = max - noise;
}
if (angle < min){
min = angle;
max = min + noise;
}
// Average: (no flickering):
angle = min + (max - min) / 2.0;