swiftuiuiscrollviewscrollviewhorizontalscrollviewios17

SwiftUI ScrollView sliding weird


I added .scrollTargetLayout(), and .scrollPosition(id: $scrollID) to my ScrollView, and then used ForEach in ScrollView to generate 12 rectangles, and the isTaped variable will be converted when those rectangles are clicked. There is a Spacer() below that will appear when isTaped is true. But when I click on those rectangles, they change strangely(the id on rectangle isn't the correct), and the scroll id at the top can also be seen. The scroll id is not really changed. I want to ask why this is?

here is preview: The id change weird on Xcode preview, and it also

This is the preview on Simulator

It's preview image

here is my code below:

struct WeirdScrollView: View {
    @State private var isTaped: Bool = false
    @State private var scrollID: Int? = 0
    
    var body: some View {
        VStack {
            VStack {
                Text("scroll id: \(scrollID ?? 0)")
                
                ScrollView(.horizontal, showsIndicators: false) {
                    LazyHStack(alignment: .top) {
                        ForEach(0..<12, id: \.self) { i in
                            RoundedRectangle(cornerRadius: 25)
                                .overlay {
                                    Text("id: \(i)")
                                        .foregroundStyle(Color.white)
                                }
                                .containerRelativeFrame(.horizontal, count: 3, spacing: 10.0)
                                .id(i)
                                .onTapGesture {
                                    withAnimation {
                                        isTaped.toggle()
                                    }
                                }
                        }
                    }
                    .scrollTargetLayout()
                }
                .scrollTargetBehavior(.viewAligned)
                .scrollPosition(id: $scrollID)
                
                if isTaped {
                   Spacer(minLength: 300)
                }
            }
            .frame(maxWidth: .infinity, maxHeight: .infinity)
        }
    }
}

I was originally going to make a custom Date Picker(there is only one Date Picker on screen, and user can scroll it horizontal), but when I did the above things(change isTaped), something weird happened to it. My project need scroll id to binding what rectangle is appear on screen, but when I remove the .scrollPosition(id: $scrollID), and it run very well but not fit what I need


Solution

  • I've made some changes to your code, referring to rob mayoff's answer here. As he says I use HStack as opposed to LazyHStack. As the picture below indicates, the scroll id text does change. And the ID numbers over the rectangles remain the same. One major changes is such that I have ZStack to encapsulate RoundedRectangle and the ID Text separately.

    import SwiftUI
    
    struct WeirdScrollView: View {
        @State private var isTapped: Bool = false
        @State private var scrollID: Int? = 0
    
        var body: some View {        
            VStack {
                Text("scroll id: \(scrollID ?? 0)")
                ScrollView(.horizontal, showsIndicators: false) {
                    HStack {
                        ForEach(0..<12, id: \.self) { i in
                            ZStack {
                                RoundedRectangle(cornerRadius: 25)
                                    .frame(maxWidth: .infinity, maxHeight: isTapped ? 300 : .infinity)
                                    .containerRelativeFrame(.horizontal, count: 3, spacing: 10.0)
                                    .onTapGesture {
                                        withAnimation {
                                            isTapped.toggle()
                                            scrollID = i
                                        }
                                    }
                                Text("id: \(i)")
                                    .foregroundStyle(Color.white)
                            }
                        }
                    }
                    .scrollTargetLayout()
                }
                .scrollTargetBehavior(.viewAligned)
                .scrollPosition(id: $scrollID)
            }
        }
    }
    

    enter image description here