Thanks for being a part of WWDC25!

How did we do? We’d love to know your thoughts on this year’s conference. Take the survey here

Please provide bounds for ViewAttachmentComponent

FB17999226

Answered by Vision Pro Engineer in 843587022

As Sydney suggested, if you read the bounds in the make closure you will get a bounds of 0. If you have state changes that trigger the update closure to be called you can read the bounds there.

You can also use the onGeometryChange(for:of:action:) view modifier to get the new bounds when the view changes size. The following reads the view size from both within the view containing the RealityView and the view that is provided to the ViewAttachmentComponent:

struct ContentView: View {
    @PhysicalMetric(from: .meters) var oneMeter = 1.0
    @State var showMoreEntity = Entity()
    @State var showMoreHeight: CGFloat = 0

    var body: some View {
        RealityView { content in
            showMoreEntity.components.set(ViewAttachmentComponent(rootView: ShowMoreView()
                .onGeometryChange(for: CGFloat.self) { proxy in
                    proxy.frame(in: .local).height
                } action: { width in
                    showMoreHeight = width
                }))
            content.add(showMoreEntity)
        }
        .ornament(attachmentAnchor: .scene(.bottomFront)) {
            Text("View Height:\n- \(showMoreHeight, specifier: "%.2f") meters \n- \(showMoreHeight / CGFloat(oneMeter), specifier: "%.2f") points")
            .padding(20).glassBackgroundEffect()
        }
    }
}

struct ShowMoreView: View {
    @PhysicalMetric(from: .meters) var oneMeter = 1.0
    @State var showMore: Bool = false
    @State var viewHeight: CGFloat = 0

    var body: some View {
        VStack {
            Text("Height: \(viewHeight, specifier: "%.2f") points - \(viewHeight / oneMeter, specifier: "%.2f") meters")
            Toggle(isOn: $showMore) { Text("Show more") }
            if showMore { Text("Some more text") }
        }
        .padding(20).glassBackgroundEffect()
        .onGeometryChange(for: CGFloat.self) { proxy in
            proxy.frame(in: .local).height
        } action: { width in
            viewHeight = width
        }
    }
}

Let us know if you have any questions!
Michael

Hi @stuffmc ,

Could you test this code snippet and tell me if it works for you:

import SwiftUI
import RealityKit
import RealityKitContent

struct ContentView: View {
    var body: some View {
        RealityView { content in
            let cube = ModelEntity(mesh: .generateBox(size: 0.1), materials: [SimpleMaterial(color: .red, isMetallic: true)])
            
            // Create a ViewAttachmentComponent
            let viewAttachmentComponent = ViewAttachmentComponent(rootView: Text("Hello, World!"))
            // Add the ViewAttachmentComponent to an entity
            let attachmentEntity = Entity(components: viewAttachmentComponent)
            // Add entity as child of cube.
            cube.addChild(attachmentEntity)
            
            content.add(cube)
            
        } update: { content in
            guard let cube = content.entities.first else { return }
            guard let attachmentComponentChild = cube.children.first else { return }

            if let viewAttachment = attachmentComponentChild.components[ViewAttachmentComponent.self] {
                let boundsViewAttachment = viewAttachment.bounds.max
                    // Get the view attachment component's bounds itself
                print("ViewAttachmentComponent Update: ", boundsViewAttachment)
                print("")
                    // Get the entity with the view attachment's bounds.
                print("Entity with ViewAttachmentComponent Update: ", attachmentComponentChild.visualBounds(relativeTo: nil).extents)
                print("")
            }
        }
    }
}

I'm curious if you were also looking for the bounds in the update or in the make closure. I'd expect the print statements to be showing bounds, not 0s.

Thank you!

Sydney

Accepted Answer

As Sydney suggested, if you read the bounds in the make closure you will get a bounds of 0. If you have state changes that trigger the update closure to be called you can read the bounds there.

You can also use the onGeometryChange(for:of:action:) view modifier to get the new bounds when the view changes size. The following reads the view size from both within the view containing the RealityView and the view that is provided to the ViewAttachmentComponent:

struct ContentView: View {
    @PhysicalMetric(from: .meters) var oneMeter = 1.0
    @State var showMoreEntity = Entity()
    @State var showMoreHeight: CGFloat = 0

    var body: some View {
        RealityView { content in
            showMoreEntity.components.set(ViewAttachmentComponent(rootView: ShowMoreView()
                .onGeometryChange(for: CGFloat.self) { proxy in
                    proxy.frame(in: .local).height
                } action: { width in
                    showMoreHeight = width
                }))
            content.add(showMoreEntity)
        }
        .ornament(attachmentAnchor: .scene(.bottomFront)) {
            Text("View Height:\n- \(showMoreHeight, specifier: "%.2f") meters \n- \(showMoreHeight / CGFloat(oneMeter), specifier: "%.2f") points")
            .padding(20).glassBackgroundEffect()
        }
    }
}

struct ShowMoreView: View {
    @PhysicalMetric(from: .meters) var oneMeter = 1.0
    @State var showMore: Bool = false
    @State var viewHeight: CGFloat = 0

    var body: some View {
        VStack {
            Text("Height: \(viewHeight, specifier: "%.2f") points - \(viewHeight / oneMeter, specifier: "%.2f") meters")
            Toggle(isOn: $showMore) { Text("Show more") }
            if showMore { Text("Some more text") }
        }
        .padding(20).glassBackgroundEffect()
        .onGeometryChange(for: CGFloat.self) { proxy in
            proxy.frame(in: .local).height
        } action: { width in
            viewHeight = width
        }
    }
}

Let us know if you have any questions!
Michael

Thanks both of you. Now I got more idea why this wasn't working when I showed it to Sydney in the labs, but also, Allan from RealityKit got me covered in the next Lab by pointing at the new SpatialContainer.

ViewAttachmentComponent Update:  SIMD3<Float>(0.036764707, 0.008455883, 0.0)
Entity with ViewAttachmentComponent Update:  SIMD3<Float>(0.073529415, 0.016911766, 0.0)

PS @Michael: You meant to write points not meters, right, in the Text?

@stuffmc

Good catch. In reformatting the code before posting, I missed swapped them around in the ornament. On launch, both views should say around 103 points / 0.08 meters. I use a geometry reader to convert the points to meters in order to show both values.

Thanks,
Michael

Please provide bounds for ViewAttachmentComponent
 
 
Q