我的应用程序使用CMMotionManager来跟踪设备运动,但iOS始终以标准设备方向(底部的主页按钮)返回设备运动数据。
为了使运动数据与UIView的方向相同,我积累了从视图向下到窗口的视图转换,如下所示:
CGAffineTransform transform = self.view.transform;
for (UIView *superview = self.view.superview; superview; superview = superview.superview) {
CGAffineTransform superviewTransform = superview.transform;
transform = CGAffineTransformConcat(transform, superviewTransform);
}
这个转换在iOS 6&7,但iOS 8更改了旋转模型,现在无论设备的方向如何,视图都会返回身份转换(无旋转)。来自运动管理器的数据仍然固定在标准方向。
在iOS 8下,监控UIDevice旋转通知并手动计算四个转换似乎是获得此转换的一种方法,但它似乎也很糟糕,因为设备方向不一定与我的视图方向匹配(即,iPhone上的上行方向是通常不支持的设备方向)。
在iOS8下,将CMMotionManager的输出定向到特定UIView的最佳方式是什么?
虽然不是很明显,但在iOS8及更高版本中,建议使用转换协调器。
在viewWillTransition(to:with:)
中,协调器可以在您调用的任何方法的完成块中向您传递采用UIViewControllerTransitionCoordinatorContext
的对象(UIKit使用的默认协调器实际上是它自己的上下文,但事实并非如此)。
上下文的targetTransform
属性是在动画结束时应用于界面的旋转。请注意,这是一个相对变换,而不是接口的最终绝对转换。
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
}
}
虽然旧方法仍然有效,但当您需要协调动画转换时,例如在使用图形框架或使用自定义布局时,此API会更加灵活。
我找不到直接计算变换的方法,所以当在我的视图控制器中收到willRotateToInterfaceOrientation:消息时,我更改了代码以手动计算设置变换,如下所示:
- (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;
}