SweetPiggy
SweetPiggy

Reputation: 85

Weird ScrollView behaviour when its inside of moving View. SwiftUI

I have container view which can be draged around and it has scrollview inside with bunch of buttons. When i drag the container view scrollViews starts to jump up and down weirdly, also buttons' hitboxes start be way off from actual buttons. (You can see my gif) But when I touch scrollview everything gets back to normal. Demo weird scrollview

This code is purely for testing

That's the main view

    struct ContentView: View {
    @State var width : CGFloat = 300
    @State var height : CGFloat = 300
    var body: some View {
        VStack{
            SecondView(width: width, height: height){
                ScrollView{
                    VStack{
                        ForEach(0...10, id : \.self){ i in
                            
                            TestButton(number: i)
                            
                        }
                    }
                }
            }
            Slider(value: $width, in: 100...500)
            Slider(value: $height, in: 100...500)
        }
    }
}

That's the dragable view

    struct SecondView<Content : View> : View {
    var width : CGFloat
    var height : CGFloat
    var content : () -> Content
    @GestureState private var dragState = DragState.inactive
    @State var position : CGSize = CGSize(width: 0, height: 0)
    var body : some View {
        let dragGesture = DragGesture().updating($dragState){ drag, state, transition in
            state = .dragging(translation: drag.translation)
            
        }.onEnded({drag in
            self.position.height+=drag.translation.height
            self.position.width+=drag.translation.width
        })
        return VStack{
            Handle()
            
            content().padding()
            
        }.frame(width: width, height: height).background(Color.yellow).cornerRadius(10)
            .offset(x: self.position.width + dragState.translation.width, y: self.position.height + dragState.translation.height)
            .gesture(dragGesture)
        
    }
    
    enum DragState {
        case inactive
        case dragging(translation : CGSize)
        
        
        var translation : CGSize {
            switch self {
            case .inactive:
                return .zero
            case .dragging(let translation):
                return translation
            }
        }
        
        var isDragging : Bool {
            switch self {
            case .inactive:
                return false
            case .dragging:
                return true
            }
        }
    }
}

I'm not sure if it is a bug or it's me doing something wrong, but looks like bug Thanks in advance for answers and suggestions

Upvotes: 4

Views: 725

Answers (1)

Asperi
Asperi

Reputation: 257503

The .offset modifier does not change views layout, so moved view really remains on the same place and hit areas remains on same place, it just drawn in different location.

Thus .offset does not fit for your goal, instead refactor to use .position, which really changes view hierarchy (but affects entire layout as well, so your floating pane should be placed in separated ZStack to avoid others).

Upvotes: 2

Related Questions