I'm trying to use my custom UIView in SwiftUI using UIViewRepresentable and I want my UIView to have the same size as I set in.frame() so that I can use it like this:
MyViewRepresentable()
.frame(width: 400, height: 250, alignment: .center)
For example, I can set a frame as a property:
struct MyViewRepresentable: UIViewRepresentable {
var frame: CGRect
func makeUIView(context: Context) -> UIView {
let myView = MyView(frame: frame)
return view
}
func updateUIView(_ uiView: UIView, context: Context) {}
}
Usage:
struct ContentView: View {
var body: some View {
MyViewRepresentable(frame: CGRect(x: 0, y: 0, width: 400, height: 250))
.frame(width: 400, height: 250, alignment: .center)
}
}
It is not a solution and I wonder how to make it right.
If MyView
has correct internal layout (which depends only on own bounds), then there is not needs in external additional limitation, ie
struct MyViewRepresentable: UIViewRepresentable {
func makeUIView(context: Context) -> UIView {
return MyView(frame: .zero)
}
func updateUIView(_ uiView: UIView, context: Context) {}
}
will be exactly sized below having 400x250 frame
struct ContentView: View {
var body: some View {
MyViewRepresentable()
.frame(width: 400, height: 250, alignment: .center)
}
}
if it is not then internal MyView layout has defects.
If Asperi's answer did not work out for you, then it's probably as they said: the internal MyView layout has defects.
To resolve this matter, you have a couple options:
viewDidLoad
override func viewDidLoad() {
super.viewDidLoad()
// 1. View Hierarchy
self.addChild(self.mySubview)
self.view.addSubview(self.mySubview.view)
self.mySubview.didMove(toParent: self)
// 2. View AutoLayout Constraints
self.mySubview.view.translatesAutoresizingMaskIntoConstraints = false
NSLayoutConstraint.activate([
view.leadingAnchor.constraint(equalTo: self.mySubview.view.leadingAnchor),
view.trailingAnchor.constraint(equalTo: self.mySubview.view.trailingAnchor),
view.topAnchor.constraint(equalTo: self.mySubview.view.topAnchor),
view.bottomAnchor.constraint(equalTo: self.mySubview.view.bottomAnchor)
])
}
viewDidLayoutSubviews
Simply within your UIViewController
, set subviews frames in viewDidLayoutSubviews
.
override func viewDidLoad() {
super.viewDidLoad()
// 1. Add your subviews once in `viewDidLoad`
self.addChild(self.mySubview)
self.view.addSubview(self.mySubview.view)
self.mySubview.didMove(toParent: self)
}
override func viewDidLayoutSubviews() {
super.viewDidLayoutSubviews()
// 2. Layout your subviews `viewDidLayoutSubviews`
// Update subview frame size
// Must be done in `viewDidLayoutSubviews`
// Otherwise in `viewDidLoad` the bounds equal `UIScreen.main.bounds`, even if you used explicit frame within SwiftUI and used GeometryReader to pass the `CGSize` yourself to this UIViewController!
let mySubviewFrame = self.view.bounds
self.mySubview.view.frame = mySubviewFrame
}
frame
and bounds
properties on the UIView.autoResizingMask
uses archaic springs and struts. See autoResizingMask
, this answer , and this article .VStack
and HStack
. This is only for SwiftUI and all the above applies to UIKit only.Probably should have made a small dev article out of this.
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.