如何正确更新与“updateUIViewController”相关的“frame”

问题描述 投票:0回答:1

我正在使用 this 相机库,其中作者将

AVCaptureVideoPreviewLayer
包装在
UIViewControllerRepresentable
link)内,以将其用作相机预览。在
updateUIViewController
内部,作者使用
frame
DispatchQueue.main.async
更新进行排队:

    func updateUIViewController(_ uiViewController: UIViewController, context: Context) {
        previewLayer.videoGravity = gravity
        if previewLayer.superlayer == nil {
            uiViewController.view.layer.addSublayer(previewLayer)
        }
        // print(uiViewController.view.bounds) -- point A
        DispatchQueue.main.async {
            // print(uiViewController.view.bounds) -- point B
            self.previewLayer.frame = uiViewController.view.bounds
        }
    }

point A
point B
之间可能存在差异,这是有道理的,因为使用
DispatchQueue.main.async
不能保证排序,但我并不完全相信这种方法是正确的。我希望能够使用
frame
之类的东西设置此视图的
Preview().frame(width: 350, height: 500)
。然而,这里缺乏排序意味着根据应用程序/视图的其他部分,
view.frame
更新会按照未知的时间表进行。例如以下内容:

import SwiftUI
import Aespa

@Observable
class ViewModel {
    @ObservationIgnored var aespaSession = Aespa.session(with: AespaOption(albumName: nil))
    @ObservationIgnored var preview: InteractivePreview {
        aespaSession.interactivePreview(
            gravity: .resizeAspectFill,
            option: InteractivePreviewOption()
        )
    }
    var show = false
}

struct ContentView: View {
    @State var viewModel = ViewModel()

    var body: some View {
        ZStack {
            VStack {
                Spacer()
                Button("Show Camera Preview") {
                    viewModel.show.toggle()
                }
            }
            .ignoresSafeArea()
            .zIndex(0)

            if viewModel.show {
                VStack {
                    viewModel.preview
                        .frame(width: 350, height: 500)
                    Spacer()
                }
                .zIndex(1)
            }
        }
    }
}

打印:

Point A: (0.0, 0.0, 393.0, 852.0)
Point B: (0.0, 0.0, 350.0, 500.0)

但是,如果您将代码更改为其他内容,也许是

.zIndex(0)
处的不同背景(我不会在这里显示确切的代码,因为我的应用程序并不简单),它可能会打印:

Point A: (0.0, 0.0, 393.0, 852.0)
Point B: (0.0, 0.0, 393.0, 852.0)

所以我的问题是。

view.frame
的正确设置方法是什么?
updateUIViewController
显然是按 some 确定性顺序调用的,但在 bound“解决”之前,
不是
。我没有看到神奇的“updateViewOneLastTime”方法?

ios swift swiftui uiview uikit
1个回答
0
投票

听起来你正在寻找

viewDidLayoutSubviews
,每当视图控制器的
view.bounds
发生变化时就会调用它。创建一个
UIViewController
子类并覆盖它。

class PreviewViewController: UIViewController {
    var previewLayer: AVCaptureVideoPreviewLayer?
    
    override func viewDidLayoutSubviews() {
        previewLayer?.frame = view.frame
    }
}

然后更改

UIViewControllerRepresentable
实现中的方法以使用该子类。在适当的情况下将预览层传递给视图控制器子类。

func makeUIViewController(context: Context) -> PreviewViewController {
    let viewController = PreviewViewController()
    viewController.view.backgroundColor = .clear
    uiViewController.previewLayer = previewLayer
    
    return viewController
}

func updateUIViewController(_ uiViewController: PreviewViewController, context: Context) {
    previewLayer.videoGravity = gravity
    if previewLayer.superlayer == nil {
        uiViewController.view.layer.addSublayer(previewLayer)
    }
    uiViewController.previewLayer = previewLayer
}

func dismantleUIViewController(_ uiViewController: PreviewViewController, coordinator: ()) {
    previewLayer.removeFromSuperlayer()
}
© www.soinside.com 2019 - 2024. All rights reserved.