首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >用CMMotionManager iPhone实现快速运动

用CMMotionManager iPhone实现快速运动
EN

Stack Overflow用户
提问于 2013-09-10 22:30:15
回答 2查看 1.2K关注 0票数 1

我使用CMMotionManager在我的视图中移动按钮、图像等,因为设备是向前、向后、右、左倾斜的。我得到态度,俯仰和滚动,然后使用这些值的字符串,表示像素放置在屏幕上。

这是我如何获得信息的方法

代码语言:javascript
复制
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]];
                   }];

我就是这样指派他们的。

代码语言:javascript
复制
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和.01the值上升到更大的值,从-.40值和4.4值得到更小的值时,它们的处理方法是一样的。我对y轴也做了同样的事情。-.01和.01为284,-.20和.20为264。然而,在这种情况下,数字从-.01上升,从.01下降。

以下是一些例子

代码语言:javascript
复制
//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,但这似乎没有帮助。

是否有人对这种行为有任何经验和了解或有任何建议。

我还添加了这个部分来移动按钮上下和侧对侧。使用这种方法,按钮上下左右移动到任何位置的手机。

代码语言:javascript
复制
//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);

这是一种视差运动。

EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2013-09-11 18:56:20

有几种反应:

  1. 我可能建议使用gravity而不是attitude,因为它很好地代表了设备的物理方向。
  2. 我可能只是更新数值,而不是使用字符串来保存值。
  3. 而不是所有这些if语句,只需要一个表示视图应该如何放置的公式。
  4. 如果您想要移动一组视图,则应该将它们放在一个UIView中(通常称为“容器视图”,不要与IB中同名的自定义容器控件混淆),然后移动容器视图。

因此,如果使用autolayout,我可能具有以下属性:

代码语言:javascript
复制
@property (nonatomic, strong) CMMotionManager *motionManager;
@property CGFloat top;
@property CGFloat left;

然后,我可以更新自动收费约束,如下所示:

代码语言:javascript
复制
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;
}];

或者如果不使用自动收费表:

代码语言:javascript
复制
@property (nonatomic, strong) CMMotionManager *motionManager;
@property CGPoint originalCenter;

代码语言:javascript
复制
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的一部分)来更新视图(如果需要的话)。因此:

代码语言:javascript
复制
@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;

代码语言:javascript
复制
- (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;
    }
}
票数 4
EN

Stack Overflow用户

发布于 2014-05-23 03:05:12

我做了以下工作:在一个可调窗口内取最大值和最小值(闪烁噪声)并取平均值。不再振荡了!

下面是我的代码,以避免在五月应用程序中闪烁:

代码语言:javascript
复制
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;
票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/18729788

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档