1

当设备向前、向后、向右、向左倾斜时,我正在使用 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 上升到 0.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";}

这样,从一个方向到下一个方向的连续流动。

但是我有一个小问题。当手机向前倾斜并从 0.2 面朝上方向转变为 0.2 面朝下方向时。我有一个生涩的动作。在 faceUp .2 按钮等中,突然向左移动,当它移动到 faceDown .20 时,它们向右移动。否则,按钮等以 0.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);

这是一种视差运动的东西。

4

2 回答 2

4

几个反应:

  1. 我可能会建议使用gravity而不是attitude,因为它很好地代表了设备的物理方向。

  2. 我可能只是更新数值,而不是使用字符串来保存值。

  3. 而不是所有这些if陈述,只需要一个表示视图应该如何放置的公式。

  4. 如果你想移动一堆视图,你应该把它们放在一个UIView(通常称为“容器视图”,不要与 IB 中的同名自定义容器控件混淆)中,然后移动容器视图。

所以,如果使用自动布局,我可能有以下属性:

@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;
}];

或者如果不使用自动布局:

@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;
    }
}
于 2013-09-11T18:56:20.400 回答
0

我做了以下事情:在可调节窗口(闪烁噪声)内取最大值和最小值并取平均值的数学运算。没有更多的振荡!!!

这是我的代码,以避免在可能的应用程序中闪烁:

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;
于 2014-05-23T03:05:12.940 回答