Skip to content

Unable to use url-image as header background #2

@Cacauu

Description

@Cacauu

I use the url-image library in one of the apps I'm building to load images from a server into a SwiftUI Image view. I've tried to migrate the view to use the ScrollViewReactiveHeader and put the URLImage into the header part of it - without any success. The view always displays with 0 height, therefore making the ScrollViewReactiveHeader invisible. See below for a snippet that shows how I'm trying to use both libraries together:

var body: some View {
        NavigationView {
            ScrollViewReactiveHeader(header: {
               URLImage(url) { image in
                    image
                        .resizable()
                        .aspectRatio(contentMode: .fill)
                        .scaledToFill()
                        .clipped()
                        .frame(height: 300)
                }
            }, headerOverlay: {
                [...]
            }, body: {
                [...]
            }, configuration: .init(showStatusBar: true, backgroundColor: nil))
        }
    }

I've also tried wrapping the URLImage in a VStack with a fixed height but that didn't help either. I'd be happy if you could provide any hints on what to do or where the problem might be :)

Activity

trentguillory

trentguillory commented on Jan 17, 2022

@trentguillory
Member

Hey, thanks for reaching out. This is an issue that's been previously reported to me (not through Github Issues). From what I've seen, AsyncImage and URLImage report back a nil height to enclosing GeometryReaders, even after their content has loaded. I'm not sure why this is.

I do know that Kingfisher works as expected, though - after loading, the height is accurate and will be displayed properly inside of ScrollViewReactiveHeader. I'll be doing more testing of this myself when I get the chance, but I'm worried that it's outside the scope of our control with this library.

As for your simplified test of wrapping the URLImage in a VStack, I've noticed oddities with that too. The best simple test that works is to use truly static views. Either a rectangle with a set height or an Image with a local asset - these work as expected.

The best workaround I can provide at the moment is to import Kingfisher for remote images. Let me know how that goes!

Cacauu

Cacauu commented on Feb 5, 2022

@Cacauu
Author

Hey, thank you for getting back to this! I only now got around to test Kingfisher. Sadly, it still doesn't work as expected. I have tried the ScrollViewReactiveHeader with static images (just normal Image in SwiftUI, no other library) with no problem, but anything that loads from remote sources doesn't seem to work. I have once again added the Kingfisher code to this. Another probably helpful Information is that, if I pass an empty body to the ScrollViewReactiveHeader, it loads the header background and displays it centered in the View.

I was also wondering if this might be related to the fact that I'm loading content for the body property after initially showing the view. The body shows a placeholder at first and then switches to a list (as you can see in the code). I hope this helps you to better understand what I'm doing and maybe helps to solve this problem 😊

var body: some View {
        NavigationView {
            ScrollViewReactiveHeader(header: {
                VStack {
                    if let angebot = someOptional {
                        KFImage(angebot.imageURL)
                            .placeholder {
                                Image(systemName: "arrow.2.circlepath.circle")
                                    .font(.largeTitle)
                                    .opacity(0.3)
                            }
                            .retry(maxCount: 3, interval: .seconds(5))
                            .resizable()
                            .aspectRatio(contentMode: .fill)
                            .scaledToFill()
                            .clipped()
                            .frame(height: 300)
                            .frame(minWidth: 0, maxWidth: .infinity)
                        
                    } else {
                        Image("someImage")
                            .resizable()
                            .aspectRatio(contentMode: .fill)
                            .scaledToFill()
                            .clipped()
                            .frame(height: 300)
                    }
                    Spacer()
                }
                .frame(height: 300)
            }, headerOverlay: {
                VStack(alignment: .leading) {
                    Spacer()
                    Text("\(anotherOptional ?? "Der Eisbus ist für euch unterwegs!")")
                        .font(Font.headline.bold())
                        .multilineTextAlignment(.leading)
                        .padding()
                        .foregroundColor(Color("EisbusStyledText"))
                        .frame(minWidth: 0, maxWidth: .infinity)
                        .materialBackground()
                }
                .frame(height: 300)
                .frame(minWidth: 0, maxWidth: .infinity)
            }, body: {
                    if model.state == .upToDate {
                        VStack {
                            Picker("...", selection: $selectedView) {
                                Text("Eissorten").tag(0)
                                Text("Eisspezialitäten").tag(1)
                            }
                            .pickerStyle(.segmented)
                            .padding(.leading)
                            .padding(.trailing)
                            .padding(.top)
                            if selectedView == 0 {
                                EissortenList(anOptionalArray ?? [], kugelPreis: moreOptionals ?? 99.9, sahnePreis: andMoreOptionals ?? 99.9, bus: bus)
                                    .frame(minHeight: 0, maxHeight: .infinity)
                            } else if selectedView == 1 {
                                SomeList(eisbecher: anotherOptionalArray ?? [])
                            }
                            #if DEBUG
                                Text("Bus: \(bus)")
                            #endif
                        }
                    }
                    else {
                        VStack(alignment: .center) {
                            Spacer()
                            GenericPlaceholder()
                            if self.model.state == .error {
                                Text("Fehler beim Aktualisieren!")
                            } else {
                                Text("Lädt...")
                            }
                        }
                        .padding()
                    }
            }, configuration: .init(showStatusBar: true, backgroundColor: nil))
                .navigationBarItems(leading:
                    Button("Fertig") {
                        DispatchQueue.main.async {
                            self.presentationMode.wrappedValue.dismiss()
                        }
                    })
                    .navigationBarTitle(Text("..."), displayMode: .inline)
        }
    }
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

      Development

      No branches or pull requests

        Participants

        @Cacauu@trentguillory

        Issue actions

          Unable to use url-image as header background · Issue #2 · swiftui-library/scrollview-reactive-header