stonko1994/SimultaneouslyScrollView

Horizontal ScrollView

Closed this issue · 5 comments

Hi,

First, great idea for a package! I have been fighting with this functionality for 2 days. I'm not sure if I implement it wrong or if that's just how it is, but this is not working for a horizontal view for me.

I use SwiftUI and the structure of my code is somehow like this

import SwiftUI
import SimultaneouslyScrollView
import Introspect

class ViewModel: ObservableObject {
    @Published var simultaneouslyScrollViewHandler = SimultaneouslyScrollViewHandlerFactory.create()
}

struct UserAddInfoTable: View {
    [...]
    
    @ObservedObject var viewModel = ViewModel()
        
    var body: some View {
        VStack {

            //Header
            ScrollView(.horizontal) {
                HStack (spacing: 0){
                    ForEach(players, id: \.self) { player in
                      [...]
                        }
                    }
                }.padding(.leading, geometry.size.width * 0.22)
            }
            .introspectScrollView { viewModel.simultaneouslyScrollViewHandler.register(scrollView: $0) }

            ScrollView {
                HStack {
                    // Category
                    VStack(alignment: .leading) {
                       [...]
                    }
                
                    // Columns
                    ScrollView(.horizontal) {
                             [...]
                    }
                    .introspectScrollView { viewModel.simultaneouslyScrollViewHandler.register(scrollView: $0) }
                }
            }
        }
    }
}

I try to synchronize the Header and Columns and the output is like this - no effect. I thought it is because of nesting the second ScrollView but even If I extrude it to be a stand-alone one, the effect is still not visible.

Nagranie.z.ekranu.2023-07-19.o.19.30.51.mov

I would be grateful for an information If I break the logic somehow (I'm new to Swift) or if the package is not working for a horizontal view :)

Nevertheless, great job! 🔥

Hey @GabrielaGradys,

thank you for reporting the problem. This is definitely unexpected and should work. I will have a look at this.

Hi,
Thank you for the quick response. I might find the funny little nightmares responsible for this strange behaviour.
I did not include them in my code snippet, because they seem irrelevant (my mistake, apologise).

Here I create a tiny file that shows the bug and what caused it:

import SwiftUI
import SimultaneouslyScrollView
import Introspect

class ViewModel: ObservableObject {
    @Published var simultaneouslyScrollViewHandler = SimultaneouslyScrollViewHandlerFactory.create()
}

struct TestScrolling: View {
    var testText = ["Test", "Test2", "Test3"]
    
    @ObservedObject var viewModel = ViewModel()
        
    var body: some View {
        GeometryReader { geometry in
            VStack {
                //Header
                ScrollView(.horizontal) {
                    HStack (spacing: 0){
                        ForEach(testText, id: \.self) { text in
                            Text(text)
                                .foregroundColor(Color.blue)
                                .padding(.trailing, 20)
                            }
                    }.padding(.leading, geometry.size.width * 0.22)
                }
                .introspectScrollView { viewModel.simultaneouslyScrollViewHandler.register(scrollView: $0) }

                ScrollView {
                    HStack {
                        ForEach(testText, id: \.self) {text in
                            // Columns
                            ScrollView(.horizontal) {
                                ForEach(testText, id: \.self) { text in
                                    Text(text).foregroundColor(Color.blue)
                                }
                            }
                            .introspectScrollView { viewModel.simultaneouslyScrollViewHandler.register(scrollView: $0) }
                        }
                    }
                }
            }
            // Uncomment any to see the bug
//            .cornerRadius(geometry.size.width * 0.1)
//            .shadow(color: .gray.opacity(0.6), radius: 10, x:0, y: 0)
        }
    }
}

struct TestScrolling_Previews: PreviewProvider {
    static var previews: some View {
        TestScrolling()
    }
}

Any of those two lines break synchronizing of the scroll if they appear on the ScorllView parent, but I tested it out also in a couple of different places and not only there they break the synchronizing.

.cornerRadius(geometry.size.width * 0.1)
 .shadow(color: .gray.opacity(0.6), radius: 10, x:0, y: 0)

I hope this additional info will help you to fix the bag :)

Thank you for the details. That helped a lot. 💪

I was able to reproduce the bug as you described it, but not all the time. Sometimes it worked well, but sometimes I was able to observe the described behaviour 🤔

I also got some deprecation methods from .introspectScrollView. Apparently they updated their library and API to a more stable version.

Once I updated to the new API of SwiftUIIntrospect, the bug was gone. 🪄

Can you try updating Introspect to 0.10.0 and do the following changes:

- .introspectScrollView { viewModel.simultaneouslyScrollViewHandler.register(scrollView: $0) }
+ .introspect(.scrollView, on: .iOS(.v13, .v14, .v15, .v16, .v17)) {
+     viewModel.simultaneouslyScrollViewHandler.register(scrollView: $0)
+ }

Bug details:

It looks like that when the bug occurred, the old Introspect method was called with the wrong ScrollView. Instead of the nested .horizontal ScrollViews, the closure was called with with the outer .vertical ScrollView.

This behaviour was no longer observed after updating to the new APIs.

Also, this matches with the updated README description from Introspect:

By default, .introspect works directly on its receiver. This means calling .introspect from inside the view you're trying to introspect won't have any effect. This is different to the original Introspect module in which some views would implicitly allow introspection from within. This is because most of the time it's more stable and predictable to introspect views directly, but there are times when it's not possible or simply too inflexible for library developers.

Thank you so much, for me also bug disappear after updating Introspect :)
I totally understand how hard it is to maintain a library that depends on another one and thanks for your time to find a solution for this issue :)

That's part of the game 🙂

I'll update the README with all the new information accordingly 👍