WWDC22 SALE: Save 50% on all my Swift books and bundles! >>

SwiftUI WebView... are we at the bottom of the scrollView?

Forums > SwiftUI

I've implemented the "WebView" solution demonstrated by @NigelGee in "SOLVED: Unable to loadHTMLString" in order to display a lengthy HTML document in a SwiftUI contentView.

I want the user to scroll to the end of the document before presenting a "Next" button. How do I let the parent contentView know the scrollView of the WKWebView is at its bottom?

Thank you!

--Bill Judd

   

Looks like others in the forums were trying to solve a similar problem.

Did you review this thread?

See-> Fun with scrollView

PS: Please tell me you're not trying to make a user scroll to the end of a User Agreement to imply that they read it? Please don't.

   

@Obelix, thanks for the pointer.

FYI, the document is not a EULA or anything like that. The app is part of a research study, approved by an Institutional Review Board. Users interested in participating will be signing an informed consent agreement. The study coordinators have specified the full text of the agreement should be presented to the user before the user can agree to participate.

   

I honestly tried to think through this issue.

GeometryReader tells you the size of object you see, the real estate of an onscreen form, or part of a form, etc.

But the issue is your consent agreement might be larger than the view it's displayed in. Also, if a user has adaptive text turned on, the font, by their selection, might be a size larger than one that you calculate.

Clearly you need to dynamically determine that your user has scrolled to the end.

I read about ScrollViewReader in Apple's documentation. I feel this is the place where you'll find your answer. But I was not able to come up with workable code. It's an interesting problem. Maybe I'll get a spark on the commute home, or someone else (place bets on someone else!!) will find your solution.

See-> Scroll View Reader

   

Thanks, @Obelix, for giving this some energy... I appreciate it.

We've decided on an alternate presentation of the content, a seequential presentation of SwiftUI views, an agreement section at a time. Tedious for the user, yes, but they'll only go thru it once and never see it again, although they will receive a signed pdf of the agreement for their records.

Thanks again!

--Bill

   

Hi @WBJ

I don't know if I'm too late with a proposition. ScrollViewReader seems only be usable to programatically move the scrolling position to an element. If you want to read the position of an element, you will have to use GeometryReader.

I've implemented a simple detection whether we reached the end of a scroll view by adding a hidden Text element at the end. Comparing the Y position of this element with the heigth of the ScrollView, I can trigger an action as soon as it becomes visible.

This is something which might also be usable to load new elements as soon as one reaches the end of a list.

struct ContentView: View {

    @State private var readToEnd = false
    @State private var scrollViewHeight = CGFloat.infinity

    @Namespace private var scrollViewNameSpace

    var body: some View {

        NavigationView {
            VStack {
                ScrollView {
                    Text(eula)
                    Text("hidden tag")
                        .hidden()
                        .background(
                            GeometryReader { proxy in
                                Color.clear
                                    .onChange(of: proxy.frame(in: .named(scrollViewNameSpace))) { newFrame in
                                        if newFrame.minY < scrollViewHeight {
                                            readToEnd = true
                                        }
                                    }
                            }
                        )
                        .border(Color.red)
                }
                .background(
                    GeometryReader { proxy in
                        Color.clear
                            .onChange(of: proxy.size, perform: { newSize in
                                let _ = print("ScrollView: ", newSize)
                                scrollViewHeight = newSize.height
                            })
                    }
                )
                .coordinateSpace(name: scrollViewNameSpace)

                NavigationLink("Accept", destination: Text("Welcome and Thank you!"))
                    .opacity(readToEnd ? 1 : 0)
                    .animation(.default, value: readToEnd)
            }
            .padding(.horizontal)
            .navigationTitle("EULA")
        }
    }

    let eula = Array(repeating: """
Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet.

""", count: 10).joined(separator: "").trimmingCharacters(in: .whitespacesAndNewlines)
}

See the video I've added to the Gist: Video

   

Save 50% in my Black Friday sale.

SAVE 50% To celebrate WWDC22, all our books and bundles are half price, so you can take your Swift knowledge further without spending big! Get the Swift Power Pack to build your iOS career faster, get the Swift Platform Pack to builds apps for macOS, watchOS, and beyond, or get the Swift Plus Pack to learn advanced design patterns, testing skills, and more.

Save 50% on all our books and bundles!

Sponsor Hacking with Swift and reach the world's largest Swift community!

Reply to this topic…

You need to create an account or log in to reply.

All interactions here are governed by our code of conduct.

 
Unknown user

You are not logged in

Log in or create account
 

Link copied to your pasteboard.