2

I have the problem that in the example the scrollto function doesn’t work the first time the list expands over the bottom edge. After scrolling to the bottom it is working again. Perhaps these examples helps to find the underlying problem, which I can’t figure out:

  1. when removing the most inner VStack it is working the first time

  2. When putting a text for example over the adding button and giving a high enough height of frame it is also working the first time

    struct ContentView: View{
    
    @State var sp = [1,2,3,4,5]
    var body: some View{
                VStack{
                    Text("asdf")
                  .frame(height: 90)
                    ScrollView{
                        ScrollViewReader{scrollReader in
                            VStack{
                                VStack{
                                    ForEach(sp,id:\.self){p in
                                        Text("\(p)").frame(height: 50)
                                    }
                                }
                                Button("add"){
                                    sp.append((sp.last ?? 0) + 1)
                                }
                                Spacer(minLength: 60)
                                    .id("bottom")
                            }
                            .frame(maxWidth: .infinity)
                            .border(Color.green)
                            .onChange(of: sp.count){_ in
                                scrollReader.scrollTo("bottom")
                            }
                        }
                    }
                    .border(Color.black)
                }
    }
    
    }
    
sheldor
  • 115
  • 12
  • I had a similar issue, rate limiting scrollTo solved it for me (as answerd here: https://stackoverflow.com/questions/75289675/scrollviewreader-scrollto-anchor-not-working-reliably/76116925#76116925) – Oded Ben Dov Apr 27 '23 at 05:10

2 Answers2

3

Remove your VStacks as they are unnecessary and are interfering with the operation of the Scrollview. Essentially, everything you are getting out of the ForEach is a "cell". With the VStack's, you are putting EVERYTHING into 1 cell, and then expecting things to work. ScrollView is looking for the multiple cells, so give them to it.

struct ContentView: View {
    @State var sp = [1,2,3,4,5]
    var body: some View{
        VStack{
            Text("asdf")
                .frame(height: 90)
            ScrollView{
                ScrollViewReader{scrollReader in
                    ForEach(sp,id:\.self){p in
                        Text("\(p)").frame(height: 50)
                    }
                    Button("add"){
                        sp.append((sp.last ?? 0) + 1)
                    }
                    Spacer(minLength: 60)
                        .id("bottom")
                        .frame(maxWidth: .infinity)
                        .border(Color.green)
                        .onChange(of: sp.count){_ in
                            scrollReader.scrollTo("bottom")
                        }
                }
            }
            .border(Color.black)
        }
    }
}
Yrb
  • 8,103
  • 2
  • 14
  • 44
  • My Problem is that in the project the scrollview is really long. If I put group containers around some views does this also breaks the scrolling behavior? – sheldor Jan 12 '22 at 19:15
  • Are you saying your are using 10+ views in a `ScrollView()` that are hard coded? – Yrb Jan 12 '22 at 20:38
  • Yes. I have a sheet view with different sections, where one can add a new object. The object has different properties and the view begins with a date picker than a title for the next section then a list view,… All these components I have put into a scrollview. At last there is a custom list view where some other objects which are related to this new object are listed. Because of this I hope that I could leave the vstack for the list. With adding a new subobject I want to scroll to the bottom. I hope this description makes it more clear. – sheldor Jan 12 '22 at 22:13
  • Can you update your code with a true example? I don't know the answer to this. I would try `Group` as it is not supposed to implement any modifications, other than to get around the 10 view limit. – Yrb Jan 13 '22 at 01:30
  • You wrote "multiple cells". Isn't it possible to use containers inside the scrollView? Isn't the spacer at the bottom independent from the other views around them? To imitate the List View from SwiftUI I use a VStack with a corner Radius so that the upper padding isn't that high. I think I should write a list View only with Foreach then with a conditional mask around the first and last element. Then it should work like you suggested. – sheldor Jan 13 '22 at 19:43
-1

Since It does not work on the first time/click. So set a timer to execute your code again after a few milliseconds. I have set 100 milliseconds so that the ScrollView scrolls instantly.

 Handler handler = new Handler(); 
 handler.postDelayed(new Runnable() { 
 public void run() {
      mainScrollView.scrollTo(0,mainScrollView.getHeight());// Your code here
     }  
  }, 100);// Delay time in milliseconds