Как изменить режим содержимого uiimageview во время выполнения?

У меня есть UIViewController с UIImageView, если я коснусь экрана, я хочу, чтобы UIImageView изменил свой contentMode. Но я обнаружил, что это не работает с некоторыми изображениями, в основном с AVCaptureSession.

Скриншоты: Заполнение пропорций

введите здесь описание изображения

Соответствие пропорций

введите здесь описание изображения

Я также обнаружил, что он работает нормально, когда я меняю ориентацию устройства на альбомную и обратно. Но когда я тапаю, экран снова не работает.

Подгонка пропорций после изменения ориентации на альбомную и обратно (я хочу, чтобы она выглядела каждый раз при подгонке сторон)

введите здесь описание изображения

Мой код:

Контроллер камеры:

class CameraController: UIViewController {

private var captureSession = AVCaptureSession()
private var captureDevice: AVCaptureDevice!
private var capturePhotoOutput = AVCapturePhotoOutput()
private var previewLayer: AVCaptureVideoPreviewLayer!

override func viewDidLoad() {
    super.viewDidLoad()

    setupCaptureSession()
    setupCaptureDevice()
    setupInputAndOutput()
    setupPreviewLayer()
    startCaptureSession()

    setupLayout()
}

private func setupCaptureSession() {
    captureSession.sessionPreset = .photo
}

private func setupCaptureDevice() {
    guard let device = AVCaptureDevice.DiscoverySession(deviceTypes: [.builtInWideAngleCamera], mediaType: AVMediaType.video, position: .back).devices.first else { return }

    captureDevice = device
}

private func setupInputAndOutput() {
    do {
        let captureDeviceInput = try AVCaptureDeviceInput(device: captureDevice)
        captureSession.addInput(captureDeviceInput)

        let captureSettings = AVCapturePhotoSettings(format: [AVVideoCodecKey: AVVideoCodecType.jpeg])
        capturePhotoOutput.setPreparedPhotoSettingsArray([captureSettings], completionHandler: nil)
        captureSession.addOutput(capturePhotoOutput)
    } catch {
        print(error.localizedDescription)
    }
}

private func setupPreviewLayer() {
    previewLayer = AVCaptureVideoPreviewLayer(session: captureSession)
    previewLayer.videoGravity = .resizeAspectFill
    previewLayer.connection?.videoOrientation = .portrait
    previewLayer.frame = view.frame
    view.layer.insertSublayer(previewLayer, at: 0)
}

private func startCaptureSession() {
    captureSession.startRunning()
}

private func setupLayout() {
    let captureButton = UIButton(frame: CGRect(x: 0, y: 0, width: 44, height: 44))
    captureButton.backgroundColor = .white
    captureButton.layer.cornerRadius = 22
    captureButton.addTarget(self, action: #selector(didPressCaptureButton), for: .touchUpInside)
    captureButton.center.x = view.center.x
    captureButton.center.y = view.frame.height - 50
    view.addSubview(captureButton)
}

@objc private func didPressCaptureButton() {
    let settings = AVCapturePhotoSettings()
    capturePhotoOutput.capturePhoto(with: settings, delegate: self)
}
}

extension CameraController: AVCapturePhotoCaptureDelegate {

func photoOutput(_ output: AVCapturePhotoOutput, didFinishProcessingPhoto photo: AVCapturePhoto, error: Error?) {
    guard let imageData = photo.fileDataRepresentation() else { return }
    guard let image = UIImage(data: imageData) else { return }

    print("Image size: ", image.size)

    let previewController = PreviewController()
    previewController.image = image
    present(previewController, animated: true, completion: {
        self.captureSession.stopRunning()
    })
}
}

Контроллер предварительного просмотра:

class PreviewController: UIViewController {

var imageView: UIImageView!
var image: UIImage!

override func viewDidLoad() {
    super.viewDidLoad()

    setupImageView()
}

func setupImageView() {
    imageView = UIImageView(image: image)
    imageView.contentMode = .scaleAspectFill
    view.addSubview(imageView)
    imageView.addConstraintsToFillSuperview()
}

override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
    let contentMode: UIViewContentMode = imageView.contentMode == .scaleAspectFill ? .scaleAspectFit : .scaleAspectFill
    imageView.contentMode = contentMode
}

}

Что я здесь делаю неправильно?

Спасибо!


person Tomas Kypry    schedule 03.06.2018    source источник
comment
Вместо того, чтобы менять режим просмотра изображения, что, если вы замените представление изображения другим?   -  person matt    schedule 03.06.2018
comment
попробуйте вызвать layoutSubViews() после того, как вы измените режим содержимого.   -  person Elhoej    schedule 03.06.2018
comment
layoutSubviews() — это то, что вы вызываете при работе внутри UIView. Но ваш код выглядит так, как будто он из UIViewController, поэтому правильный метод для вызова — view.setNeedsLayout().   -  person dfd    schedule 03.06.2018
comment
layoutSubview() и view.setNeedsLayout() не работают :(   -  person Tomas Kypry    schedule 03.06.2018
comment
@matt Добавление другого UIImageView и изменение его свойства isHidden работает. Но это просто не похоже на правильный способ сделать это.   -  person Tomas Kypry    schedule 03.06.2018
comment
На каком основании вы это говорите? Мне это кажется более правильным, чем пытаться изменить режим контента. Вы можете попробовать изменить режим содержимого, а затем сказать setNeedsDisplay, но в целом идея изменения режима содержимого представления изображения, когда оно уже отображает изображение, кажется отвратительной. Тот факт, что вы чувствуете, что вам нужно это сделать, сам по себе является Плохим Запахом, на мой взгляд.   -  person matt    schedule 03.06.2018
comment
Также у меня возникли некоторые проблемы с обновлением UIImageView при изменении их содержимого или режима содержимого; так что, возможно, обмен изображениями — это самый простой выход.   -  person matt    schedule 10.06.2018


Ответы (1)


Вы можете изменить ImageView contentMode во время выполнения с помощью:

    self.imageView.contentMode = newContentMode
    self.imageView.setNeedsDisplay()
person Amir Ardalan    schedule 08.09.2020