我有一个 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
}
onChange
根本没有被调用。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 有自己的布局系统,无法与 UIKit 结合使用。使用 SwiftUI,父视图决定子视图的大小和位置。
这意味着,例如,不得更改
frame
中的 UIViewRepresentable
属性,就像您在代码中所做的那样。
苹果对此也说得很清楚在开发者文档中:
SwiftUI 完全控制 UIKit 视图的中心、边界、框架和变换属性的布局。不要通过自己的代码直接在 UIViewRepresentable 实例管理的视图上设置这些与布局相关的属性,因为这与 SwiftUI 冲突并导致未定义的行为。
另请注意,
updateUIView
专门用于响应 SwiftUI 中的 state 更改,而不是用于 layout 更改。
如果您想对 SwiftUI 视图的大小变化做出反应,您必须在 GeometryReader 的帮助下完成此操作,或者使用您自己的 Layout 实现。