禁用UIView的自动旋转功能

21

我的应用程序由一个工具栏和一个放置在后台UIView中的AVCaptureVideoPreviewLayer组成。 我希望看到该工具栏根据设备方向旋转,因此在我的主ViewController中,我实现了以下函数:

- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
{
    return (interfaceOrientation == UIInterfaceOrientationPortrait
            || interfaceOrientation == UIInterfaceOrientationLandscapeLeft
            || interfaceOrientation == UIInterfaceOrientationLandscapeRight);
}
这段代码运行良好,但当界面方向改变时,我发现背景UIView(带有视频层)也随之旋转,因此我的视频视图现在向左或向右播放90度...这真的不太好!所以我的问题是:是否有任何方法可以在特定的UIView上禁用自动旋转动画?我看到了一个类似于这个问题的问题:Disabling autorotate for a single UIView,但答案并不能解决我的问题,我真的需要让背景视图不动,而不是通过一种“对抗动画”来绕过问题。因此,我决定提出这个话题。有什么想法吗?谢谢!

我有同样的问题。你解决了吗?它能在iOS 6上运行吗?你可以给一个完整的答案吗?非常感谢。 - A.Vila
5个回答

11

这篇帖子指明了正确的方向。为了使 AVCaptureVideoPreviewLayer 不随设备旋转,我将其包装在一个 UIView 中,并以相反的方向动画化该视图:

- (void) willAnimateRotationToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation duration:(NSTimeInterval)duration {

    float rotation;

    if (toInterfaceOrientation==UIInterfaceOrientationPortrait) {
        rotation = 0;
    } else
    if (toInterfaceOrientation==UIInterfaceOrientationLandscapeLeft) {
        rotation = M_PI/2;
    } else
    if (toInterfaceOrientation==UIInterfaceOrientationLandscapeRight) {
        rotation = -M_PI/2;
    }

    [UIView animateWithDuration:duration animations:^{
        cameraPreview.transform = CGAffineTransformMakeRotation(rotation);
        cameraPreview.frame = self.view.frame;
    }];
}

看起来有点绕,但是它的动画很流畅。其他在预览图层上方的视图会自动旋转,正如它们应该做的那样。


我稍微修改了框架代码:CGRect f = cameraPreview.frame; cameraPreview.transform = CGAffineTransformMakeRotation(rotation); cameraPreview.frame = f; - colinta
嗨,谢谢你的回复。self.view.frame 不会返回旋转后的视图框架吗?如果是横屏,它将返回横屏框架,如果是竖屏,则返回竖屏框架等等。如果我错了,请纠正我。 - Malloc
@Dimitri 给一些时间,整件事情看起来非常可疑。这真的是处理我遇到的任何问题的最佳方式吗?我真的很怀疑。在iOS 8中,willAnimateRotationTo...这种方法不再存在。尝试在超级视图的layoutSubviews中执行类似的操作。无需添加动画块,因为在屏幕旋转期间已经调用了layoutSubviews。界面方向应通过[UIApplication sharedApplication].statusBarOrientation访问,但确保值在布局期间与您的预期相匹配。 - Anthony Mattox
这里还有一件非常奇怪的事情,@Malloc可能正在考虑这个问题。假设cameraPreviewself.view的子视图,cameraPreview.frame = self.view.frame;应该改为cameraPreview.frame = self.view.bounds;。期望的行为可能是意外发生的,因为视图填充了整个屏幕。也许在横向模式下,框架的宽度和高度也应该交换?无论如何,不建议设置转换视图的框架,所以我不确定为什么会起作用。 - Anthony Mattox

2
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation {
  return NO;
}

或者你是说只在特定视图显示时禁用它?如果是这样,您可以使用UIView的isDescendantOfView方法来检查。


1
好的,我不想禁用整个界面旋转,只是想在主视图控制器的视图层次结构中禁用特定的UIView。这意味着当我旋转设备时,我可以看到工具栏旋转,但视频视图不会旋转。 - Thomas Desert
这不是UIView上的方法 - 它在UIViewController上。因此,它将禁用整个视图层次结构的旋转。 - colinta

2
我终于找到了一个明智的答案,不用再纠结于“防止旋转动画”之类的东西了!
关键是使用UIViewController来处理预览层(非旋转视图)和另一个用于实际界面。使用shouldAutorotateToInterfaceOrientation配置两个控制器的旋转选项:(代码在上面的答案中)
- 预览视图控制器应设置为不旋转 - 界面视图控制器应设置为旋转到需要的方向
重要的一点是通过直接将它们添加到窗口来保持您的视图分离。我在AppDelegate中执行此操作。
[self.window addSubview:previewViewController.view];
[self.window addSubview:interfaceViewController.view];
self.window.rootViewController = interfaceViewController;
[self.window makeKeyAndVisible];

这将把您的视频预览放在背景中,然后在其上添加界面视图。界面可以自由旋转而不会影响预览。

需要注意的一点是:您的界面视图的背景应该是透明的,否则会阻挡预览。


这种方法是可行的。不过我最终采用了略微不同的方式,即为预览层创建了一个“背景”UIWindow,并在另一个“主”UIWindow中放置了其余的UI(并且该窗口具有透明背景,以便预览层可见)。 - alasker

1

我遇到了同样的问题,尽管简单地在AVCaptureVideoPreviewLayer上设置方向属性是不够的。另一个问题是,在iPhone上,CALayer不支持布局管理器,因此当设备旋转时,视频层的框架可能不正确。

我通过使用自定义UIView来包含AVCaptureVideoPreviewLayer,并覆盖此视图的layoutSubviews方法来修复此问题,以确保视频层的框架始终正确设置。这也是设置方向属性的好地方。也就是说,我的UIView看起来像:

@implementation VideoPreview

@synthesize previewLayer;

- (void) layoutSubviews {
    if (previewLayer) {
        // set the correct orientation for the video layer
        previewLayer.orientation = [[UIDevice currentDevice] orientation];

        // and set its frame to that of its parent UIView
        previewLayer.frame = self.bounds;
    }
}

- (void) addPreviewLayer: (AVCaptureVideoPreviewLayer *) videoLayer {
    previewLayer = videoLayer;
    [self.layer addSublayer:videoLayer];
}

@end

-2

试试这个:

myVideoCaptureLayer.orientationSupported = NO;

5
据我理解,orientationSupported属性是只读的,并且用于判断设备是否能够改变视频方向。 如果为真,则可以将“方向”属性更改为正确的值(AVCaptureVideoOrientationPortrait,AVCaptureVideoOrientationLandscapeLeft等)。 感谢您让我朝着正确的方向前进! - Thomas Desert

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接