How to change uiimageview content mode at runtime?

1.1k Views Asked by At

I have a UIViewController with an UIImageView, if I tap the screen, i want the UIImageView to change its contentMode. But I found out that this is not working with some images, mainly those from AVCaptureSession.

Screenshots: Aspect fill

enter image description here

Aspect fit

enter image description here

I also found out that it's working fine when I change device orientation to landscape and back. But when I tap the screen is not working again.

Aspect fit after changed orientation to landscape and back (this is how I want it to look everytime in aspect fit)

enter image description here

My code:

CameraController:

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()
    })
}
}

PreviewController:

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
}

}

What am I doing wrong here?

Thank You!

1

There are 1 best solutions below

0
On

You can change ImageView contentMode on runtime with:

    self.imageView.contentMode = newContentMode
    self.imageView.setNeedsDisplay()