问题
My application uses CMMotionManager to track device motion, but iOS always returns device motion data in the standard device orientation (home button at the bottom).
To get the motion data into the same orientation as my UIView, I accumulate the view transforms from my view down to the window like this:
CGAffineTransform transform = self.view.transform;
for (UIView *superview = self.view.superview; superview; superview = superview.superview) {
CGAffineTransform superviewTransform = superview.transform;
transform = CGAffineTransformConcat(transform, superviewTransform);
}
This transform gets calculated correctly under iOS 6 & 7, but iOS 8 changes the rotation model and now the views always return the identity transform (no rotation) no matter how the device is oriented. The data from the motion manager is still fixed in the standard orientation though.
Monitoring UIDevice rotation notifications and manually calculating the four transforms seems like one approach to getting this transform under iOS 8, but it also seems bad since the device orientation won't necessarily match my view's orientation (ie, upside on iPhone is a device orientation not normally supported).
What's the best way to get the output from CMMotionManager into the orientation of a specific UIView under iOS 8?
回答1:
Although not very obvious, the recommended way of doing this in iOS 8 and later is with transition coordinators.
In viewWillTransition(to:with:)
, the coordinator can pass you an object adopting UIViewControllerTransitionCoordinatorContext
in the completion blocks of whichever of its methods you call (the default coordinator used by UIKit is actually its own context, but this isn't necessarily the case).
The context's targetTransform
property is the rotation to be applied to the interface by the end of the animation. Note this is a relative transform, not the resulting absolute transform of the interface.
override func viewWillTransition(to size: CGSize, with coordinator: UIViewControllerTransitionCoordinator) {
super.viewWillTransition(to: size, with: coordinator)
let animation: (UIViewControllerTransitionCoordinatorContext) -> Void = { context in
// Update animatable properties.
}
coordinator.animate(alongsideTransition: animation) { context in
// Store or use the transform.
self.mostRecentTransform = context.targetTransform
}
}
While the old approach still works, this API is a bit more flexible when you need to coordinate animated transitions, such as when working with graphics frameworks or using a custom layout.
回答2:
I couldn't find a way to directly calculate the transform, so instead I changed my code to calculate set the transform manually when a willRotateToInterfaceOrientation: message is received in my view controller, like this:
- (void)willRotateToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation duration:(NSTimeInterval)duration {
CGAffineTransform transform;
switch (toInterfaceOrientation) {
case UIInterfaceOrientationLandscapeLeft:
transform = CGAffineTransformMake(
0, -1,
1, 0,
0, 0);
break;
case UIInterfaceOrientationLandscapeRight:
transform = CGAffineTransformMake(
0, 1,
-1, 0,
0, 0);
break;
case UIInterfaceOrientationPortraitUpsideDown:
transform = CGAffineTransformMake(
-1, 0,
0, -1,
0, 0);
break;
case UIInterfaceOrientationPortrait:
transform = CGAffineTransformIdentity;
break;
}
self.motionTransform = transform;
}
来源:https://stackoverflow.com/questions/25691721/how-do-i-adjust-cmmotionmanager-data-for-orientation-under-ios-8