Snapshot of Swiftui View Is Partially Cut Off

Snapshot of SwiftUI view is partially cut off

I also recently noticed this issue. I tested on different Simulators (for example, iPhone 8 and iPhone 13 Pro) and realized that the offset seems always half the status bar height. So I suspect that when you call drawHierarchy(in:afterScreenUpdates:), internally SwiftUI always takes safe area insets into account.

Therefore, I modified the snapshot() function in your View extension by using the edgesIgnoringSafeArea(_:) view modifier, and it worked:

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

let targetSize = controller.view.intrinsicContentSize
view?.bounds = CGRect(origin: .zero, size: targetSize)
view?.backgroundColor = .clear

let renderer = UIGraphicsImageRenderer(size: targetSize)

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

SwiftUI: Prevent Image() from expanding view rect outside of screen bounds

You have to limit the frame size of the out-of-bounds Image before it is being picked up by the ZStack to avoid the ZStack to grow and so the Overlay to go out of position.

edit: aheze shows with his answer a way around using GeometryReader by putting the Image into the background of Overlay() with .background(Image()..). This avoids the usage of ZStack and GeometryReader completely and is possibly a cleaner solution.

Based on parent view size

struct IgnoringEdgeInsetsView2: View {
var body: some View {
ZStack {
GeometryReader { geometry in
Image("smile")
.resizable()
.aspectRatio(contentMode: .fill)
.edgesIgnoringSafeArea(.all)
.frame(maxWidth: geometry.size.width,
maxHeight: geometry.size.height)
}
Overlay()
}
}
}

Based on screen size

struct IgnoringEdgeInsetsView: View {
var body: some View {
ZStack {
Image("smile-photo")
.resizable()
.aspectRatio(contentMode: .fill)
.edgesIgnoringSafeArea(.all)
.frame(maxWidth: UIScreen.main.bounds.width,
maxHeight: UIScreen.main.bounds.height)
Overlay()
}
}
}

Example

Detecting sheet was dismissed on iOS 13

Is there a way to detect that the presented view controller sheet was dismissed?

Yes.

Some other function I can override in the parent view controller rather than using some sort of delegate?

No. "Some sort of delegate" is how you do it. Make yourself the presentation controller's delegate and override presentationControllerDidDismiss(_:).

https://developer.apple.com/documentation/uikit/uiadaptivepresentationcontrollerdelegate/3229889-presentationcontrollerdiddismiss


The lack of a general runtime-generated event informing you that a presented view controller, whether fullscreen or not, has been dismissed, is indeed troublesome; but it's not a new issue, because there have always been non-fullscreen presented view controllers. It's just that now (in iOS 13) there are more of them! I devote a separate question-and-answer to this topic elsewhere: Unified UIViewController "became frontmost" detection?.

SwiftUI - How to partially mask/clip an image?

create a clipped illusion) will not work

Check out the .clipped() modifier. It's the real thing, not an illusion.

struct ContentView: View {
@State var offset = CGFloat(0)

var body: some View {
Group {
Image(systemName: "circle.fill")
.foregroundColor(.red)
.offset(x: offset, y: 0)
}
.frame(width: 80, height: 80)
.border(Color.green) /// just for clarity, you can remove this
.clipped() /// use this to prevent circle from going past borders
.onAppear {
withAnimation(.linear(duration: 5)) {
offset = 100
}
}
}
}

Result:

Circle moving right and past the border, but as soon as it gets to the border it starts clipping



Related Topics



Leave a reply



Submit