2013-09-10 3 views
1

Я использую CMMotionManager для перемещения кнопок, изображений и т. Д. На мой взгляд, когда устройство наклонено вперед, назад, вправо, влево. Я получаю настройку позиции и рулон, а затем использую их для назначения значений строке, представляющей размещение пикселей на экране.jerky motion using CMMotionManager iPhone

Вот как я получить информацию

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";} 

т.д.

Я сделал их так, ось х непрерывно идет вверх и вниз (туда и обратно) на экране. то есть -01 то же самое, что и -40, 0,01 и 0,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";} 

Таким образом, существует непрерывный поток от одной ориентации к другой.

Однако у меня небольшая проблема. когда телефон перевернут вперед и переходит от ориентации .2 faceUp к ориентации .2 faceDown. Я вздрагиваю. В кнопках 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); 

Это своего рода движение параллакса.

+0

Я считаю, что проще использовать 'gravity' вместо' attitude' при поиске основного материала ориентации. Я также просто использовал бы числовые значения (корректируя ограничение 'constant' в автоматическом макете, корректируя значения« frame », если нет), что устраняет все эти операторы if. – Rob

+0

не уверен, что вы подразумеваете под этим. Однако я попытался использовать значения ускорения, но когда я их использовал, кнопка переместилась вниз, когда телефон был опрокинут вперед, но не двигался обратно, пока телефон не вернулся обратно, не встал на прежнее положение. Также я добавляю код, который я использую, чтобы переместить кнопку в моем исходном сообщении. – user1114881

+0

Не могли бы вы дать мне пример того, что вы предлагаете – user1114881

ответ

4

Пару реакций:

  1. я мог бы предложить использовать gravity, а не attitude, так как она хорошо представляет физическую ориентацию устройства.

  2. Вместо того, чтобы использовать строку для хранения значения, я могу просто обновить числовые значения.

  3. Вместо всех этих операторов if просто введите формулу, представляющую, как следует размещать представление.

  4. Если вы хотите переместить кучу видов, вы должны поместить их в UIView (обычно называемый «вид контейнера», чтобы не путать с настраиваемым контейнером в IB с тем же именем), а затем просто переместите представление контейнера.

Таким образом, при использовании autolayout, я мог бы иметь следующие свойства:

@property (nonatomic, strong) CMMotionManager *motionManager; 
@property CGFloat top; 
@property CGFloat left; 

И тогда я могу обновить autolayout ограничения, как так:

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; 

a й

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

Честно говоря, имея менеджер движения работают в основную очередь дает мне дрожь, так что я мог (а) создать 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; 
    } 
} 
+0

ОК, это отлично работает, однако, когда я иду в faceDown, движения меняются на противоположные, и я хочу, чтобы они продолжали то, как они находятся в faceUp. особенно на оси х. Вы знаете, как я применил бы классификатор ориентации устройства. то я бы просто добавил вместо вычитания. – user1114881

+0

@ user1114881 Вы можете заменить эту функцию тем, что хотите (добавьте гравитацию, а не вычитайте). И если вы поддерживаете разные ориентации, просто посмотрите на [[[UIDevice currentDevice] ориентация] ", и если пейзаж, вероятно, заменит ссылки' gravity.x' и 'gravity.y'. Аналогично, вам, возможно, придется настроить знак в зависимости от 'UIDeviceOrientationPortraitUpsideDown' или' UIDeviceOrientationPortrait' (а также 'UIDeviceOrientationLandscapeLeft' против' UIDeviceOrientationLandscapeRight'). Я уверен, что с небольшим экспериментом вы получите правильные значения. – Rob

+0

Спасибо, что у меня мало проблем с реализацией ориентации. Думаю, FaceUp и FaceDown. Я не использую пейзаж. в любом случае, спасибо – user1114881

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; 
Смежные вопросы