无法更改包装在 SwiftUI 视图内的 UIView 的框架

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

我有一个 UIView 包裹着 SwiftUI View。我后来更改了 UIView 大小,但不知何故它总是回到原始大小。

我有 SwiftUI View 像这样包裹着 UIView。这是一种方法。我尝试了多种方法,例如 KVO,但都不起作用。

struct SomeUIViewRepresentable: UIViewRepresentable {
    let uiView: UIView
    @Binding var frame: CGRect

    func makeUIView(context: Self.Context) -> UIView {
        return uiView
    }

    func updateUIView(_ uiView: UIView, context: Self.Context) {
        print("updateUIView \(uiView.frame.size) frame \(frame.size)")
        if CGSizeEqualToSize(frame.size, CGSize(width: 256, height: 144)) {
            uiView.frame = frame
            uiView.layoutIfNeeded()
        }
    }
}

struct SwiftUIView: View {

    @StateObject var model : ViewModel = .init()
    let view: UIView

    var body: some View {
        SomeUIViewRepresentable(uiView: view, frame: $model.frame)
            .frame(width: model.frame.width, height: model.frame.height)
            .onChange(of: model.frame) { newFrame in
                // Ensure that SwiftUI is notified when the frame changes
                print("SwiftUI frame updated to: \(newFrame.size)")
            }
    }
}

extension SwiftUIView {

    final class ViewModel: ObservableObject {
        @Published var frame: CGRect = CGRect(x: 0, y: 0, width: 200, height: 200)
    }
}

extension SwiftUIView.ViewModel: FrameChangeDelegate {
    func viewFrameChanged(view: UIView) {
        self.frame = view.frame // When it reaches here, the UIView is already set to a new size.
        print("viewFrameChanged \(view.frame.size) frame \(frame.size)")
    }
}


func createView() -> any View {
    let swiftUIView =  SwiftUIView(view: view)
    delegate.viewModel = swiftUIView.model

    return swiftUIView
}
  1. 为什么我换了帧却总是回到原来的帧(200, 200)?
    onChange
    根本没有被调用。
  2. 我将 UIView 框架大小更改为 (256, 144)。我注意到
    layoutSubviews
    是用新的帧大小调用的,但稍后(几乎立即)UIView
    layoutSubviews
    再次用原始大小调用。是什么让 UIView
    layoutSubviews
    被第二次调用?其内容不会改变。

注意:在调用

viewFrameChanged
委托方法之前,我已经通过调用以下方法更改了 UIView 框架。

- (void) updateSize:(CGSize)newSize {
    self.frame = CGRectMake(self.frame.origin.x, self.frame.origin.y, newSize.width, newSize.height);
    [self setNeedsLayout];
    [self layoutIfNeeded];
}

这是一些日志:

layoutSubviews: {256, 144}
viewFrameChanged (256.0, 144.0) frame (256.0, 144.0)
layoutSubviews: {200, 200}

不知何故,设置新框架

updateUIView
后不会调用
self.frame = view.frame

swiftui uiview swiftui-layout
1个回答
0
投票

SwiftUI 有自己的布局系统,无法与 UIKit 结合使用。使用 SwiftUI,父视图决定子视图的大小和位置。

这意味着,例如,不得更改

frame
中的
UIViewRepresentable
属性,就像您在代码中所做的那样。

苹果对此也说得很清楚在开发者文档中

SwiftUI 完全控制 UIKit 视图的中心、边界、框架和变换属性的布局。不要通过自己的代码直接在 UIViewRepresentable 实例管理的视图上设置这些与布局相关的属性,因为这与 SwiftUI 冲突并导致未定义的行为。

另请注意,

updateUIView
专门用于响应 SwiftUI 中的 state 更改,而不是用于 layout 更改。

如果您想对 SwiftUI 视图的大小变化做出反应,您必须在 GeometryReader 的帮助下完成此操作,或者使用您自己的 Layout 实现。

请参阅此处此处如何实现您自己的布局以及此处如何使用 GeometryReader。

© www.soinside.com 2019 - 2024. All rights reserved.