iPhone X及以上UIImagePickerController自定义cameraOverlayView被刘海遮挡适配安全区失效
适配UIImagePickerController自定义相机覆盖层的安全区显示
现有实现逻辑
你目前完成的自定义相机逻辑分为两部分:
自定义记录视图加载
cameraOverlay = RecordView.loadNib() cameraOverlay.frame = UIScreen.main.bounds cameraOverlay.buttonStartRecording.addTarget(self, action: #selector(buttonStartStopRecordingClicked), for: .touchUpInside) cameraOverlay.buttonCancel.addTarget(self, action: #selector(buttonCancelClicked), for: .touchUpInside) cameraOverlay.buttonSwitchCamera.addTarget(self, action: #selector(buttonCameraSwitchClicked), for: .touchUpInside) cameraOverlay.buttonFlash.addTarget(self, action: #selector(buttonFlashClicked), for: .touchUpInside) cameraOverlay.labelTimer.text = "00:00/\(self.secondsToHoursMinutesSeconds(inputSeconds: recordingTimeLimit))"
图片选择控制器配置
imagePicker.delegate = self imagePicker.sourceType = .camera imagePicker.mediaTypes = [kUTTypeMovie as String] imagePicker.allowsEditing = true imagePicker.cameraOverlayView = cameraOverlay imagePicker.showsCameraControls = false imagePicker.cameraFlashMode = .off imagePicker.cameraCaptureMode = .video imagePicker.cameraDevice = .rear self.present(imagePicker, animated: true, completion: nil)
问题原因
给自定义覆盖层直接赋值UIScreen.main.bounds作为frame时,这个frame是覆盖整个物理屏幕的,包含了刘海、底部Home指示条的非交互区域。在无刘海老机型上这个范围刚好和有效显示区域重合所以运行正常,但在iPhone X及后续带安全区的机型上,靠近顶部的交互元素会直接落在刘海的遮挡范围内。
修复方案
替换硬编码全屏frame的逻辑
不要手动给覆盖层设置全屏幕frame,改用AutoLayout将覆盖层的边界约束到imagePicker视图的安全区内,修改后的代码逻辑:
- 删掉原来的
cameraOverlay.frame = UIScreen.main.bounds这行代码 - 开启AutoLayout适配,将覆盖层四边和imagePicker的安全区做绑定:
cameraOverlay.translatesAutoresizingMaskIntoConstraints = false imagePicker.cameraOverlayView = cameraOverlay NSLayoutConstraint.activate([ cameraOverlay.topAnchor.constraint(equalTo: imagePicker.view.safeAreaLayoutGuide.topAnchor), cameraOverlay.bottomAnchor.constraint(equalTo: imagePicker.view.safeAreaLayoutGuide.bottomAnchor), cameraOverlay.leadingAnchor.constraint(equalTo: imagePicker.view.safeAreaLayoutGuide.leadingAnchor), cameraOverlay.trailingAnchor.constraint(equalTo: imagePicker.view.safeAreaLayoutGuide.trailingAnchor) ])
落地注意事项
- 不要在视图未完成布局时提前通过
UIScreen.main.bounds或者keyWindow的safeAreaInsets计算边距值,这种场景下拿到的安全区边距往往是0,无法正确适配刘海区域。所有约束尽量以当前控制器的safeAreaLayoutGuide作为参考锚点,这种写法会自动兼容iOS 11以下的系统,在无刘海设备上会自动降级为普通视图边界,不需要手动判断设备型号。 - UIImagePickerController的相机预览区域默认是铺满全屏幕的,如果你把覆盖层完全约束在安全区内,预览画面的上下部分会被覆盖层的不透明区域遮挡。可以根据实际UI设计调整覆盖层的边距:将不需要交互的透明区域放开到全屏幕范围,只把需要用户操作的按钮、计时器标签等元素单独约束在安全区内,兼顾预览效果和交互可用性。
内容的提问来源于stack exchange,提问作者Khadija Daruwala
相关产品推荐
相关产品推荐

