1

I have this method, to snapshot a view:

extension View {
    func snapshot(size: CGSize, colorScheme: ColorScheme) -> UIImage {
        let controller = UIHostingController(rootView: self.edgesIgnoringSafeArea(.all))
        let view = controller.view

        if view != nil {
            view!.bounds = CGRect(x: 0, y: 0, width: size.width, height: size.height)
            view!.backgroundColor = colorScheme != .dark ? Color.white.uiColor() : Color(hex: "#1b1c1e").uiColor()
        }

        let renderer = UIGraphicsImageRenderer(size: size)
        
        return renderer.image { _ in
            view?.drawHierarchy(in: controller.view.bounds, afterScreenUpdates: true)
        }
    }
}

I currently have to provide the size of the view by using GeometryReader and updating the view every time.

However, it's making my app lag a little and I would prefer getting the size inside this function.

The View I'm snapshotting is inside a ScrollView, and sometimes it's super high, others it could be empty.

Is there anyway of getting view.height where the height includes all the items, regardless of the height of the device?

My current solution is to use ChildSizeReader:

struct ChildSizeReader<Content: View>: View {
    @Binding var size: CGSize
    let content: () -> Content
    var body: some View {
        ZStack {
            content()
                .background(
                    GeometryReader { proxy in
                        Color.clear
                            .preference(key: SizePreferenceKey.self, value: proxy.size)
                    }
                )
        }
        .onPreferenceChange(SizePreferenceKey.self) { preferences in
            self.size = preferences
        }
    }
}

struct SizePreferenceKey: PreferenceKey {
    typealias Value = CGSize
    static var defaultValue: Value = .zero

    static func reduce(value _: inout Value, nextValue: () -> Value) {
        _ = nextValue()
    }
}

Like so:

struct ChildSizeReaderExample: View {
    @State var textSize: CGSize = .zero
    var body: some View {
        VStack {
            ChildSizeReader(size: $textSize) {
                Text("Hello I am some arbitrary text.")
            }
            Text("My size is \(textSize.debugDescription)!")
        }
    }
}

(Reference)

And then I manually call .snapshot(size: textSize)

But I would prefer not to use ChildSizeReader and get the full height inside the snapshot() function.

view.height returns the max of the device height, so I'm not sure what else to do?

Please let me know if I'm missing something.

Heron. F
  • 232
  • 3
  • 13

0 Answers0