Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

DrivingScrollView not selected after startup #32

Open
Lumentus opened this issue Feb 2, 2022 · 3 comments
Open

DrivingScrollView not selected after startup #32

Lumentus opened this issue Feb 2, 2022 · 3 comments

Comments

@Lumentus
Copy link
Contributor

Lumentus commented Feb 2, 2022

The problem

In our productive app we have a problem with the new way to determine the driving scroll view. Namely the modified ScrollView is not actually driving after the overlay is first shown. After moving the sheet to a different notch the ScrollView is actually driving and everything is working as expected.
Unfortunately I have not been able to create a simple example for this, since this seems to be some kind of race condition. This file here basically shows what we do in my companies app: https://github.com/Lumentus/DynamicOverlay/blob/driving-scroll-view-test/DynamicOverlay_Example/DynamicOverlay_Example/View/DrivingScrollViewTest.swift
This code alone will unfortunately not fail (on my simulators), but with a change to the ActivatedOverlayArea struct, that I added mainly to get better insight into what is going on, this will produce the problems that we have in our app too. The changed file can be seen here: https://github.com/Lumentus/DynamicOverlay/blob/driving-scroll-view-test/Source/Internal/Handle/ActivatedOverlayArea.swift

My diagnosis

I have tried to figure out what exactly is going wrong here and with two debug outputs I think I have been able to get to the bottom of the problem, though I have no idea how to fix this.
I added two outputs that print the ActivatedOverlayArea that is present at that location. One to DynamicOverlayScrollViewProxy.findScrollView and one to the onPreferenceChange closure in OnDrivingScrollViewChangeViewModifier.body.
This produces something like the following output when the scroll view is correctly found:

placeholder appeared
preferenceChange: ActivatedOverlayArea(spots: [])
content appeared
findScrollView: ActivatedOverlayArea(spots: [])
preferenceChange: ActivatedOverlayArea(spots: [DynamicOverlay.ActivatedOverlayArea.(unknown context at $10ffa8ba0).Spot(frame: (0.0, 44.80908203125, 0.0, 0.0))])
preferenceChange: ActivatedOverlayArea(spots: [DynamicOverlay.ActivatedOverlayArea.(unknown context at $10ffa8ba0).Spot(frame: (104.0, 65.28483072916669, 182.0, 589.7151692708333))])
findScrollView: ActivatedOverlayArea(spots: [DynamicOverlay.ActivatedOverlayArea.(unknown context at $10ffa8ba0).Spot(frame: (0.0, 44.80908203125, 0.0, 0.0))])
findScrollView: ActivatedOverlayArea(spots: [DynamicOverlay.ActivatedOverlayArea.(unknown context at $10ffa8ba0).Spot(frame: (104.0, 65.28483072916669, 182.0, 589.7151692708333))])

And something like the following when the ScrollView is not driving after startup:

placeholder appeared
preferenceChange: [] from 1643807010.705128
content appeared
findScrollView: [] from 1643807010.705204
preferenceChange: [DynamicOverlay.ActivatedOverlayArea.(unknown context at $10de51bd0).Spot(frame: (0.0, 44.80908203125, 0.0, 0.0))] from 1643807010.837788
preferenceChange: [DynamicOverlay.ActivatedOverlayArea.(unknown context at $10de51bd0).Spot(frame: (104.0, 65.28483072916669, 182.0, 589.7151692708333))] from 1643807010.86582
findScrollView: [DynamicOverlay.ActivatedOverlayArea.(unknown context at $10de51bd0).Spot(frame: (0.0, 44.80908203125, 0.0, 0.0))] from 1643807010.837788
findScrollView: [DynamicOverlay.ActivatedOverlayArea.(unknown context at $10de51bd0).Spot(frame: (104.0, 65.28483072916669, 182.0, 589.7151692708333))] from 1643807010.86582
findScrollView: [] from 1643807010.705128

What is pretty obvious is that in the erroneous case the last call to findScrollView is called with an ActivatedOverlayArea that has no spots set, while in the successful case there is a spot defined. Judging by the timestamps that I added to the ActivatedOverlayArea for debug purposes (and causes the error to surface on my simulator), the ActivatedOverlayArea used for the last findScrollView is the first one that was received in the preferenceChange event.

@gaetanzanella
Copy link
Collaborator

gaetanzanella commented Feb 5, 2022

Hey @Lumentus, thank you for the detailed issue!

It is hard to tell without a sample code... it sounds like the area is not propagated correctly.
Could you try to put a dispatch async in the onChange modifier? A classic SwiftUI fix 😅.

func body(content: Content) -> some View {
        content.onPreferenceChange(DynamicOverlayScrollViewProxyPreferenceKey.self, perform: { value in
            print("preferenceChange: \(value)")
            DispatchQueue.main.async { handler(DynamicOverlayScrollViewProxy(area: value)) }
        })
    }

@Lumentus
Copy link
Contributor Author

Lumentus commented Feb 9, 2022

@gaetanzanella Unfortunately that does not fix the problem. Did you try my branch with a simulator of your own?

@Kondamon
Copy link

Kondamon commented Jul 12, 2023

I can reproduce this issue. Whenever the overlay gets hidden (.fractional(0)) and then reappears on the screen the scrollView is not driving the overlay anymore. When I drag to another notch (e.g. max) then it starts to work again as long as the overlay remains visible.

A quick workaround is to disable the scrollView in the initial position. However, this doesn't resolve the underlying issue in the SDK.

ScrollView {
     content
}
. scrollDisablediOS15(self.notch == .min)

struct DisableScrollingModifier: ViewModifier {
    var isDisabled: Bool
    
    func body(content: Content) -> some View {
    
        if #available(iOS 16.0, *) {
            content
            .scrollDisabled(isDisabled)
        } else {
            if isDisabled {
                content
                    .simultaneousGesture(DragGesture(minimumDistance: 0))
            } else {
                content
            }
        }
    }
}

public extension View {
    func scrollDisablediOS15(_ isDisabled: Bool) -> some View {
        modifier(DisableScrollingModifier(isDisabled: isDisabled))
    }
}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants