Reputation: 12641
With UIInterpolatingMotionEffect, twist the iPhone, and you can have an image move.
Now: imagine a red block you will "bounce around" on screen, using UICollisionBehavior and UIDynamicItemBehavior. When the user twists the iPhone: I want the boxes to "start moving" WITH SIMILAR PHYSICS FEEL to using UIInterpolatingMotionEffect.
http://tinypic.com/player.php?v=b67mlc%3E&s=8#.VBVEq0uZNFx
Aside:UX explanation: the bouncy effect (example: SMS on iPhone) has the same "feel" as the parallax image effect in iOS. (By "feel" I really just mean the same speed, acceleration.) This would be a third effect: like parallax it would "move things slightly" but they would "keep moving", bouncing a little. (You could say, somewhat combining the feel of bouncy-lists-effect and and parallax-images-effect.)
Now: it's relatively easy to do what I describe, using CMAccelerometerData, and applying pushes using UIPushBehaviorModeInstantaneous. But it's a lot of messy code.
In contrast, UIInterpolatingMotionEffect is ridiculously easy to use.
Essentially, how can I get the values from UIInterpolatingMotionEffect (which I will then use as pushes). Cheers!
Simply display the values of UIInterpolatingMotionEffect?
It asks simply: how can one easily "just get" the values from UIInterpolatingMotionEffect ? ie, it seems incredible one has to go to the effort of carefully subclassing CALayer, etc.
Upvotes: 2
Views: 518
Reputation: 437592
It's an interesting notion of updating some behavior via the UIInterpolatingMotionEffect
, though I don't suspect it's designed for that. If you want to update behaviors based upon accelerometer information, I personally would have thought that the CMMotionManager
is ideal for that purpose.
The desired UX isn't entirely clear from the video clip, but it looks like that video is having things continue to slide in the direction the phone is tilted until you stop tilting the phone. If that's what you want, I'd be inclined to marry CMMotionManager
with a UIKit Dynamics UIGravityBehavior
:
self.animator = [[UIDynamicAnimator alloc] initWithReferenceView:container];
UICollisionBehavior *collision = [[UICollisionBehavior alloc] initWithItems:container.subviews];
collision.translatesReferenceBoundsIntoBoundary = YES;
[self.animator addBehavior:collision];
UIGravityBehavior *gravity = [[UIGravityBehavior alloc] initWithItems:container.subviews];
gravity.gravityDirection = CGVectorMake(0, 0);
[self.animator addBehavior:gravity];
self.motionManager = [[CMMotionManager alloc] init];
typeof(self) __weak weakSelf = self;
[self.motionManager startDeviceMotionUpdatesToQueue:[NSOperationQueue mainQueue] withHandler:^(CMDeviceMotion *motion, NSError *error) {
if (weakSelf.referenceAttitude == nil) {
weakSelf.referenceAttitude = motion.attitude;
} else {
CMAttitude *attitude = motion.attitude;
[attitude multiplyByInverseOfAttitude:weakSelf.referenceAttitude];
gravity.gravityDirection = CGVectorMake(attitude.roll * 5.0, attitude.pitch * 5.0);
}
}];
If you want them to move precisely in accordance to the attitude, stopping the movement when you stop moving the device (like UIInterpolatingMotionEffect
does), you could use a UIAttachmentBehavior
, something like:
UIAttachmentBehavior *attachment = [[UIAttachmentBehavior alloc] initWithItem:viewToAttachTo attachedToAnchor:viewToAttachTo.center];
[self.animator addBehavior:attachment];
self.motionManager = [[CMMotionManager alloc] init];
self.motionManager.deviceMotionUpdateInterval = 1.0 / 20.0;
typeof(self) __weak weakSelf = self;
CGPoint originalAnchorPoint = viewToAttachTo.center;
[self.motionManager startDeviceMotionUpdatesToQueue:[NSOperationQueue mainQueue] withHandler:^(CMDeviceMotion *motion, NSError *error) {
if (weakSelf.referenceAttitude == nil) {
weakSelf.referenceAttitude = motion.attitude;
} else {
CMAttitude *attitude = motion.attitude;
[attitude multiplyByInverseOfAttitude:weakSelf.referenceAttitude];
attachment.anchorPoint = CGPointMake(originalAnchorPoint.x + attitude.roll * 10.0, originalAnchorPoint.y + attitude.pitch * 10.0);
}
}];
Note, in both of those examples, I'm applying the adjustments to the behaviors as the device shifts from the orientation of the device when the user started the app. Thus I capture a CMAttitude
property, referenceAttitude
to be the attitude of the device when the user fired up the app, and then uses multiplyByInverseOfAttitude
on subsequent updates to apply gravity in relation to that original orientation. You could, obviously, use a predetermined attitude if you wanted, too.
But hopefully the above illustrates one approach to tackling this sort of UX.
Upvotes: 3