I am using CMMotionManager to move buttons, images etc. on my view as the device is tipped forward, backward, right, left. I get the attitude pitch and roll and then use these to assign values to a string representing pixel placement on the screen.
Here is how I get the info
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]];
}];
and this is how I assign them.
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";}
etc.
I have made them so the x axis continuously goes up and down (back and forth) on the screen. i.e. -.01 is the same as -.40, .01 and .40. and they are approached the same as you go up from -.01 and .01the values get bigger and from -.40 and 4.4 they get smaller. I did the same with y axis also. -.01 and .01 are 284 and -.20 and .20 are at 264. However in this case the numbers go up from -.01 and down from .01.
here are some examples
//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";}
In this way there is continuous flow from one orientation to the next.
However I am having a small problem. when the phone is tipped forward and passes from .2 faceUp orientation to .2 faceDown orientation. I get a jerky motion. In faceUp .2 buttons etc. move to the left all of a sudden and when it moves to faceDown .20 they move to the right. Otherwise the buttons etc. are centered at .19 and -.19 and return there to operate normally (as expected). I have tried to call DeviceOrientationFaceUp and FaceDown but this didn't seem to help.
Does anyone have any experience with this behavior and know of a fix or have any suggestions.
I also add this part to move the buttons up and down and side to side. Using this method the button up and down side to side wherever the position of the phone.
//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);
this is a kind of parallax motion thing.
A couple of reactions:
I might suggest using
gravity
rather thanattitude
, as it nicely represents the physical orientation of the device.Rather than using a string to hold the value, I might just update the numeric values.
Rather than all of those
if
statements, just have a formula that represents how the view should be placed.If you want to move a bunch of views, you should put them in a
UIView
(commonly called a "container view", not to be confused with the custom container control in IB of the same name) and then just move the container view.So, if using autolayout, I might have the following properties:
And then I can update the autolayout constraints like so:
Or if not using autolayout:
and
Frankly, having the motion manager operate in the main queue gives me the willies, so I might (a) create a
NSOperationQueue
for the motion updates and only update some class property; and (b) use aCADisplayLink
(part of the QuartzCore.framework) to update the view (if needed). Thus:and