Предотвратить вращение UIView с AVCaptureVideoPreviewLayer с помощью остальной части ViewController - PullRequest
0 голосов
/ 22 января 2019

У меня есть контроллер представления, встроенный в контроллер панели вкладок, который, помимо прочего, представляет AVCaptureVideoPreviewLayer в UIView.

Когда устройство поворачивается, я хочу, чтобы контроллер представления вращался вместе с ним, за исключением вышеупомянутого UIView.

В отличие от этого связанного вопроса , однако, я не просто вращаю / трансформирую мои другие виды в контроллере вида. Для других представлений необходимо использовать настроенное поведение поворота для автоматического размещения.

Я пробовал несколько вещей, включая простую настройку ориентации видео в портретную:

previewLayer.connection.videoOrientation = .portrait

для извлечения UIView в отдельный контроллер представления, встраивания этого контроллера представления в исходный контроллер представления и установки его свойств autoRotation

override var shouldAutorotate: Bool {
    return false
}

override var supportedInterfaceOrientations: UIInterfaceOrientationMask {
    return .portrait
}

но потом я узнал здесь , что iOS смотрит только на контроллер представления верхнего уровня для этих свойств.

Со всем, что я пробовал, предварительный просмотр видео вращается с остальной частью контроллера представления, заканчивая вбок.

Единственное, что работает, но является хакерским и иногда приводит к смещению предварительного просмотра видео, это

override func viewWillTransition(to size: CGSize, with coordinator: UIViewControllerTransitionCoordinator) {
    super.viewWillTransition(to: size, with: coordinator)

    DispatchQueue.main.asyncAfter(deadline: .now() + 0.5) {
        if let videoPreviewLayerConnection = previewLayer.connection {
            if let newVideoOrientation = AVCaptureVideoOrientation(rawValue: UIApplication.shared.statusBarOrientation.rawValue) {
                videoPreviewLayerConnection.videoOrientation = newVideoOrientation
            }
        }
    }
}

Мне в принципе нужна противоположность этого вопроса .

Как сделать так, чтобы предварительный просмотр видео не вращался, но также позволял нормально вращаться остальной части контроллера представления? (Такое же поведение, как и в приложении для iOS-камеры, за исключением того, что другие элементы пользовательского интерфейса вращаются вместо Поворот на 90 °)

1 Ответ

0 голосов
/ 22 января 2019

Следующее может быть таким же хакерским, как и ваше решение, но визуально оно выглядит чище.

В viewWillTransition Я установил аффинное преобразование PreviewView, чтобы противодействовать ориентации, заданной поворотом телефона.Это выглядит чище, чем просто установка videoOrientation, поскольку аффинное преобразование анимируется с той же скоростью, что и изменение ориентации.Это делается следующим образом.

override func viewWillTransition(to size: CGSize, with coordinator: UIViewControllerTransitionCoordinator) {
    super.viewWillTransition(to: size, with: coordinator)

    let orientation = UIDevice.current.orientation
    var rotation : CGFloat = self.previewView.transform.rotation
    switch(orientation) {
    case .portrait:
        rotation = 0.0
    case .portraitUpsideDown:
        rotation = CGFloat.pi
    case .landscapeLeft:
        rotation = -CGFloat.pi/2.0
    case .landscapeRight:
        rotation = CGFloat.pi/2.0
    default:
        break
    }
    let xScale = self.previewView.transform.xScale
    let yScale = self.previewView.transform.yScale
    self.previewView.transform = CGAffineTransform(scaleX:xScale, y:yScale).rotated(by:rotation)
    self.view.layoutIfNeeded()

}

Вот расширение CGAffineTransform, код выше использует

extension CGAffineTransform {
    public var xScale: CGFloat {
        get {return sqrt(self.a * self.a + self.c * self.c) }
    }
    public var yScale: CGFloat {
        get {return sqrt(self.b * self.b + self.d * self.d) }
    }
    public var rotation: CGFloat {
        get {return CGFloat(atan2f(Float(self.b), Float(self.a))) }
    }
}
...