iOS 9中的强制视图控制器方向

时间:2016-06-17 16:14:39

标签: ios iphone uiinterfaceorientation

我正在开发一款摄影应用,可让照片以人像或风景拍摄。由于项目的要求,我不能让设备方向自动旋转,但需要支持旋转。

使用以下定位方法时:

override func shouldAutorotate() -> Bool {
    return true
}

override func supportedInterfaceOrientations() -> UIInterfaceOrientationMask {
    if self.orientation == .Landscape {
        return UIInterfaceOrientationMask.LandscapeRight
    } else {
        return UIInterfaceOrientationMask.Portrait
    }
}

override func preferredInterfaceOrientationForPresentation() -> UIInterfaceOrientation {
    if self.orientation == .Landscape {
        return UIInterfaceOrientation.LandscapeRight
    } else {
        return UIInterfaceOrientation.Portrait
    }
}

我可以在启动时正确设置旋转。通过更改方向值并调用UIViewController.attemptRotationToDeviceOrientation(),我可以支持旋转到新的所需界面。 但是,此旋转仅在用户实际移动其设备时发生。我需要它自动发生。

我可以调用:UIDevice.currentDevice().setValue(targetOrientation.rawValue, forKey: "orientation")强制进行更改,但这会导致其他副作用,因为UIDevice.currentDevice().orientation仅从该点返回setValue。 (而且它非常脏)

我有什么遗漏?我已经考虑过关闭并启动一个新的视图控制器,但是还有其他问题,例如在解雇时会出现持续的UI故障,并立即提出一个新的视图控制器。

编辑:

以下方法对我不起作用:

编辑2:

关于潜在解决方案的想法:

  1. 直接设置方向(使用setValue)并处理iOS 9上出现的所有副作用(不接受)

  2. 我可以使用当前的解决方案并指示用户需要旋转设备。设备物理旋转后,UI会旋转,然后正确锁定到位。 (差的用户界面)

  3. 我可以找到一种强制刷新方向并在没有物理操作的情况下旋转的解决方案。 (我正在询问和寻找的内容)

  4. 手工完成。我可以纵向或横向锁定界面,并手动旋转和调整容器视图的大小。这很脏'因为它放弃了所有大小类自动布局功能并导致更重的代码。我试图避免这种情况。

3 个答案:

答案 0 :(得分:3)

我以前遇到过这个问题,我自己。我能够通过简单的解决方法来解决它(和GPUImage)。我的代码在Objective-C中,但我确信你将它转换为Swift没有问题。

我首先将项目支持的轮换设置为我希望支持的所有内容,然后覆盖相同的UIViewController方法:

-(BOOL)shouldAutorotate { 
    return TRUE; 
}

-(NSUInteger)supportedInterfaceOrientations {
    return UIInterfaceOrientationMaskPortrait;
}

允许设备旋转但在纵向模式下仍然存在。然后开始观察设备旋转:

[[NSNotificationCenter defaultCenter] addObserver:self
                                         selector:@selector(adjustForRotation:)
                                             name:UIDeviceOrientationDidChangeNotification
                                           object:nil];

如果设备处于纵向模式或横向,则更新UI:

-(void)adjustForRotation:(NSNotification*)notification
{
    UIDeviceOrientation orientation = [[UIDevice currentDevice] orientation];

    switch (orientation) {
        case UIDeviceOrientationLandscapeLeft:
        {
            // UPDATE UI
        }
            break;
        case UIDeviceOrientationLandscapeRight:
        {
            // UPDATE UI
        }
            break;
        default: // All other orientations - Portrait, Upside Down, Unknown
        {
            // UPDATE UI
        }
            break;
    }
} 

最后,GPUImage根据设备的方向渲染图像。

[_gpuImageStillCamera capturePhotoAsImageProcessedUpToFilter:last_f
                                              withCompletionHandler:^(UIImage *processedImage, NSError *error) { 
    // Process the processedImage 
}];

答案 1 :(得分:3)

我能够在这个答案的帮助下找到解决方案:Programmatic interface orientation change not working for iOS

我的基本定位逻辑如下:

// Local variable to tracking allowed orientation. I have specific landscape and
// portrait targets and did not want to remember which I was supporting
enum MyOrientations {
    case Landscape
    case Portrait
}
var orientation: MyOrientations = .Landscape

// MARK: - Orientation Methods

override func shouldAutorotate() -> Bool {
    return true

}

override func supportedInterfaceOrientations() -> UIInterfaceOrientationMask {
    if self.orientation == .Landscape {
        return UIInterfaceOrientationMask.LandscapeRight
    } else {
        return UIInterfaceOrientationMask.Portrait
    }
}

override func preferredInterfaceOrientationForPresentation() -> UIInterfaceOrientation {
    if self.orientation == .Landscape {
        return UIInterfaceOrientation.LandscapeRight
    } else {
        return UIInterfaceOrientation.Portrait
    }
}

// Called on region and delegate setters
func refreshOrientation() {
    if let newOrientation = self.delegate?.getOrientation() {
        self.orientation = newOrientation
    }
}

然后,当我想刷新方向时,我会执行以下操作:

// Correct Orientation
let oldOrientation = self.orientation
self.refreshOrientation()
if self.orientation != oldOrientation {
    dispatch_async(dispatch_get_main_queue(), {
        self.orientationRefreshing = true

        let vc = UIViewController()

        UIViewController.attemptRotationToDeviceOrientation()

        self.presentViewController(vc, animated: false, completion: nil)

        UIView.animateWithDuration(0.3, animations: {
            vc.dismissViewControllerAnimated(false, completion: nil)
        })
    })
}

此解决方案具有导致view[Will/Did]Appearview[Will/Did]Disappear同时触发所有内容的副作用。我使用本地orientationRefreshing变量来管理这些方法的哪些方面再次被调用。

答案 2 :(得分:0)

所以我查看了UIDevice的私有标题,看起来有两个setter和两个属性定义,用于定位,目前令人困惑。这就是我所看到的......

@property (nonatomic) int orientation;
@property (nonatomic, readonly) int orientation; 

- (void)setOrientation:(int)arg1;
- (void)setOrientation:(int)arg1 animated:(BOOL)arg2;

所以,当我看到你使用setValue:forKey:时,我想看到有一个合成的setter和getter,老实说,不是100%确定哪一个被设置,哪一个被承认设备......我试图在一个演示应用程序中使用setValue:forKey:无效,但是从我过去的一个应用程序中使用了这个技巧,它立即起作用了:)我希望这有帮助

UIDevice.currentDevice().performSelector(Selector("setOrientation:"), withObject: UIInterfaceOrientation.Portrait.rawValue)