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 から上がり、.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);

これは一種の視差運動です。

4

2 に答える 2

4

いくつかの反応:

  1. デバイスの物理的な向きをうまく表しているので、gravityではなくを使用することをお勧めします。attitude

  2. 文字列を使用して値を保持するのではなく、数値を更新するだけです。

  3. これらすべてのifステートメントではなく、ビューをどのように配置するかを表す式を用意してください。

  4. 多数のビューを移動する場合は、それらを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;
}];

または、自動レイアウトを使用しない場合:

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

率直に言って、メイン キューでモーション マネージャーを動作させると、私は意地悪な気持ちになり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

私は次のことを行いました: 調整可能なウィンドウ (フリッカー ノイズ) 内の最大値と最小値を取り、平均を取る計算。もう振動はありません!!!

5月のアプリでちらつきを避けるためのコードは次のとおりです。

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 に答える