I have an image that I want to present above all windows including .sheets in SwiftUI. I am using the solution pulled from the SO thread below. However when I try to use the view I get the error "Static method 'buildExpression' requires that 'TopImageView' conform to 'View'". How can I correctly present an Image above all windows in SwiftUI?
https://stackoverflow.com/a/77533196/18070009
struct ContentView: View {
@State var showImage = false
var body: some View {
TopImageView(isPresented: $showImage, image: "https://cdn.pixabay.com/photo/2015/04/23/22/00/tree-736885_1280.jpg")
}
}
struct TopImageView: ViewModifier {
@Binding var isPresented: Bool
@State private var hostingController: UIHostingController<TopImage>? = nil
let image: String
func showImage() {
let swiftUIView = TopImage(image: image)
hostingController = UIHostingController(rootView: swiftUIView)
hostingController?.view.backgroundColor = .clear
hostingController?.view.frame = CGRect(
x: 0,
y: UIScreen.main.bounds.height,
width: UIScreen.main.bounds.width,
height: 0)
if let windowScene = UIApplication.shared.connectedScenes.first as? UIWindowScene,
let window = windowScene.windows.first {
window.addSubview(hostingController!.view)
hostingController?.view.center.x = window.center.x
let contentSize = hostingController!.view.sizeThatFits(CGSize(
width: UIScreen.main.bounds.width,
height: .greatestFiniteMagnitude))
UIView.animate(withDuration: 0.5) {
hostingController?.view.frame.origin.y = window.frame.height - contentSize.height
hostingController?.view.frame.size.height = contentSize.height
}
}
}
func dismissImage() {
hostingController?.view.removeFromSuperview()
hostingController = nil
}
func body(content: Content) -> some View {
ZStack(alignment: .bottom) {
content
if isPresented {
VStack {}
.onAppear {
showImage()
}
.onChange(of: image) { newValue in
dismissImage()
showImage()
}
.onDisappear {
dismissImage()
}
}
}
}
}
struct TopImage: View {
let image: String
@State var imageHeight: Double = 0.0
@State var imageWidth: Double = 0.0
@State var opac: Double = 1.0
@State private var offset: CGPoint = .zero
@State private var lastTranslation: CGSize = .zero
var body: some View {
ZStack {
Rectangle().foregroundColor(.black).opacity(opac).ignoresSafeArea()
GeometryReader { geometry in
KFImage(URL(string: image))
.resizable()
.aspectRatio(contentMode: .fit)
.offset(x: offset.x + (widthOrHeight(width: true) - imageWidth) / 2.0, y: offset.y + (widthOrHeight(width: false) - imageHeight) / 2.0)
.background(
GeometryReader { proxy in
Color.clear
.onChange(of: proxy.size.height) { _ in
imageHeight = proxy.size.height
imageWidth = proxy.size.width
}
}
)
}
}
.ignoresSafeArea()
}
}
You've made TopImageView
a ViewModifier
, but it looks like you just want it to be a View
. You could change it to View
and change the signature of body to be var body: some View
rather than a function