У меня была эта точная проблема, и быстро выяснилось, что вокруг авторотации существует множество плохих советов, особенно потому, что iOS 8 обрабатывает ее иначе, чем предыдущие версии.
Прежде всего, вы не используете хотите применить противовращение вручную или подписаться на изменения .Выполнение контрротации по-прежнему приведет к неприглядной анимации, а устройство Ориентация не всегда совпадает с интерфейсом ориентация. В идеале вы хотите, чтобы предварительный просмотр камеры оставался по-настоящему замороженным, и ваш пользовательский интерфейс приложения соответствовал ориентации и размеру строки состояния по мере их изменения, точно так же, как и собственное приложение для камеры.
Во время изменения ориентации в iOS 8 само окно вращается, а не содержит вид (ы), который он содержит. Вы можете добавить виды нескольких контроллеров просмотра к одному UIWindow
, но только rootViewController
получит возможность ответить через shouldAutorotate()
. Несмотря на то, что вы принимаете решение о ротации на уровне контроллера представления, это фактическое вращение родительского окна, таким образом, вращение всех его подзонов (в том числе и от других контроллеров представлений).
Решение состоит из двух UIWindow
, уложенных друг на друга, каждый из которых (или нет) имеет свой собственный контроллер корневого представления. В большинстве приложений есть только один, но нет причин, по которым вы не можете иметь два и наложить их так же, как и любой другой подкласс UIView
.
Настоящая рабочая концепция, which I've also put on GitHub here. Ваш конкретный случай немного сложнее, потому что у вас есть стек содержащихся контроллеров представлений, но основная идея такая же. Я коснусь некоторых конкретных пунктов ниже.
@UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate {
var cameraWindow: UIWindow!
var interfaceWindow: UIWindow!
func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject : AnyObject]?) -> Bool {
let screenBounds = UIScreen.mainScreen().bounds
let inset: CGFloat = fabs(screenBounds.width - screenBounds.height)
cameraWindow = UIWindow(frame: screenBounds)
cameraWindow.rootViewController = CameraViewController()
cameraWindow.backgroundColor = UIColor.blackColor()
cameraWindow.hidden = false
interfaceWindow = UIWindow(frame: CGRectInset(screenBounds, -inset, -inset))
interfaceWindow.rootViewController = InterfaceViewController()
interfaceWindow.backgroundColor = UIColor.clearColor()
interfaceWindow.opaque = false
interfaceWindow.makeKeyAndVisible()
return true
}
}
Установка отрицательного застегивается на interfaceWindow
делает его немного больше, чем экран рамки, эффективно скрывает черную прямоугольную маску, увидели бы в противном случае. Обычно вы не заметите, потому что маска вращается с окном, но поскольку окно камеры фиксировано, маска становится видимой в углах во время вращения.
class CameraViewController: UIViewController {
override func shouldAutorotate() -> Bool {
return false
}
}
именно то, что вы ожидали бы здесь, просто добавить свои собственные настройки для AVCapturePreviewLayer
.
class InterfaceViewController: UIViewController {
var contentView: UIView!
override func viewDidLoad() {
super.viewDidLoad()
contentView = UIView(frame: CGRectZero)
contentView.backgroundColor = UIColor.clearColor()
contentView.opaque = false
view.backgroundColor = UIColor.clearColor()
view.opaque = false
view.addSubview(contentView)
}
override func viewWillLayoutSubviews() {
super.viewWillLayoutSubviews()
let screenBounds = UIScreen.mainScreen().bounds
let offset: CGFloat = fabs(screenBounds.width - screenBounds.height)
view.frame = CGRectOffset(view.bounds, offset, offset)
contentView.frame = view.bounds
}
override func supportedInterfaceOrientations() -> Int {
return Int(UIInterfaceOrientationMask.All.rawValue)
}
override func shouldAutorotate() -> Bool {
return true
}
}
Последний трюк отменяя отрицательную врезку мы применяли к окну, которое мы достигаем путем зачета view
такого же количества и лечения contentView
в качестве основного вида.
Для вашего приложения будет вашим контроллером панели управления, который, в свою очередь, содержит контроллер навигации и т. Д. Все эти представления должны быть прозрачными, когда появится ваш контроллер камеры, чтобы окно камеры отображалось под ним. По соображениям производительности вы можете подумать о том, чтобы оставить их непрозрачными и только установить все на прозрачное, когда камера действительно используется, и установить окно камеры на hidden
, когда это не так (при выключении сеанса захвата).
Извините, что опубликовать роман; Я не видел, чтобы это обращалось в другом месте, и мне потребовалось некоторое время, чтобы понять, надеюсь, это поможет вам и всем, кто пытается добиться такого же поведения. Даже пример приложения Apple AVCam
не справляется с этим совершенно правильно.
The example repo I posted также включает версию с уже установленной камерой. Удачи!
Вы нажимаете ViewControllerB из ViewControllerA? –
Я добавляю его в качестве подзаголовка. 'self.view.addSubview (viewController.view)' – switz