0

So I have the following in my project.

  1. ContentView ~ contains 3 vstacks.
  2. CustomView ~ a custom view with a containerView with fixed size of 300x300 that should always be centered in ContentView
  3. CustomViewRepresentable ~ a UIViewRepresentable in order to insert CustomView into ContentView.

The code for each is as follows:

ContentView

import SwiftUI
import UIKit

struct ContentView: View {
    
    var body: some View {
        VStack(alignment: .center, spacing: 0) {
            VStack {
                Color.blue
                    .frame(height: 50)
            }
            VStack {
                HStack {
                    Color.green
                        .frame(height: 100)
                    Text("Text")
                    Color.green
                        .frame(height: 100)
                }
            }
            VStack { // content view
                GeometryReader { geometry in
                    VStack {
                        CustomViewRepresentable()
                            .frame(width: geometry.size.width, height: geometry.size.height)
                            .background(.gray)
                            .border(.red, width: 1)
                    }
                    .frame(width: geometry.size.width, height: geometry.size.height)
                }
            }
        }
    }
}

struct ContentView_Previews: PreviewProvider {
    static var previews: some View {
        ContentView()
    }
}

CustomView

import UIKit

class CustomView: UIView {
    private let containerView = UIView()
    override func layoutSubviews() {
        containerView.center = self.center
    }

    func addContainerView() {
        containerView.frame = CGRect(origin: .zero, size: CGSize(width: 300, height: 300))
        addSubview(containerView)
        containerView.center = self.center
    }
}

CustomViewRepresentable

import UIKit
import SwiftUI

struct CustomViewRepresentable: UIViewRepresentable {
    typealias UIViewType = CustomView
    
    func makeUIView(context: Context) -> CustomView {
        let customView = CustomView(frame: CGRect(x: 0, y: 0, width: 300, height: 300))
        customView.addContainerView()
        return customView
    }

    func updateUIView(_ uiView: CustomView, context: Context) {
        
    }
}

The issue that I'm facing is that the containerView inside CustomView does not display unless I initialise CustomView with a frame inside the representable.

func makeUIView(context: Context) -> CustomView {
        let customView = CustomView(frame: CGRect(x: 0, y: 0, width: 300, height: 300))

I don't understand why this is needed because I'd like the CustomView to take the full width and height of the VStack that it is embedded into. Therefore I figured that just doing

CustomViewRepresentable()
   .frame(width: geometry.size.width, height: geometry.size.height)

inside the VStack should just work, but apparently it does not. So what is the best way for the CustomViewRepresentable to fill its parent while keeping the containerView always centered within it?

batman
  • 1,937
  • 2
  • 22
  • 41
  • "unless I initialise CustomView with a frame inside the representable" How else would you initialise it? `let customView = CustomView()` works just as well for me. – Sweeper Aug 28 '23 at 04:56
  • it does not work for me in the sense that if I dont set the frame, the containerView does not show at all. – batman Aug 28 '23 at 05:02
  • What do you mean by " I dont set the frame"? Please show a [mcve]. – Sweeper Aug 28 '23 at 05:04
  • inside `makeUIView`, I need to do `let customView = CustomView(frame: CGRect(x: 0, y: 0, width: 300, height: 300))` instead of just let `customView = CustomView()`. Only then does the containerView inside the CustomView show. – batman Aug 28 '23 at 05:06
  • Well I cannot reproduce. The container view still appears. – Sweeper Aug 28 '23 at 05:09

1 Answers1

0

No need to provide the CustomView frame in func makeUIView(context: Context) -> CustomView function. After replacing let customView = CustomView(frame: CGRect(x: 0, y: 0, width: 300, height: 300)) code with let customView = CustomView() working at my end. Please check with the code below.

ContenView

import SwiftUI
import UIKit

struct ContentView: View {
    
    var body: some View {
        VStack(alignment: .center, spacing: 0) {
            VStack {
                Color.blue
                    .frame(height: 50)
            }
            VStack {
                HStack {
                    Color.green
                        .frame(height: 100)
                    Text("Text")
                    Color.green
                        .frame(height: 100)
                }
            }
            VStack { // content view
                GeometryReader { geometry in
                    VStack {
                        CustomViewRepresentable()
                            .background(.gray)
                            .border(.red, width: 1)
                    }
                    .frame(width: geometry.size.width, height: geometry.size.height)
                }
            }
        }
    }
}

struct ContentView_Previews: PreviewProvider {
    static var previews: some View {
        ContentView()
    }
}

CustomView

import UIKit

class CustomView: UIView {
    private let containerView = UIView()
    override func layoutSubviews() {
        containerView.center = self.center
    }

    func addContainerView() {
        containerView.frame = CGRect(origin: .zero, size: CGSize(width: 300, height: 300))
        addSubview(containerView)
        containerView.center = self.center
    }
}

CustomViewRepresentable

import UIKit
import SwiftUI

struct CustomViewRepresentable: UIViewRepresentable {
    typealias UIViewType = CustomView
    
    func makeUIView(context: Context) -> CustomView {
        let customView = CustomView(frame: CGRect(x: 0, y: 0, width: 300, height: 300))
        customView.addContainerView()
        return customView
    }

    func updateUIView(_ uiView: CustomView, context: Context) {
        
    }
}
jnpdx
  • 45,847
  • 6
  • 64
  • 94
Mohd Sultan
  • 200
  • 8