SwiftUIPager icon indicating copy to clipboard operation
SwiftUIPager copied to clipboard

[FEAT] Add trackpad scroll support

Open almagest21 opened this issue 3 years ago • 3 comments

Is your feature request related to a problem? Please describe. When using Trackpad, it requires drag and drop operation to change page.

Describe the solution you'd like For Desktop or iPad with Trackpad use-case, two finger scroll is more easier way than drag and drop page. Please consider to support to scroll pages.

Describe alternatives you've considered N/A

almagest21 avatar Jul 04 '22 06:07 almagest21

Hi @almagest21 , thanks for your feedback. I believe it's not possible to do this natively in SwiftUI? I can't find any documentation on it, the only accepted answer is "wrapping an NSView into SwiftUI and use scrollWheel". However this defeats the purpose of the library 😕

fermoya avatar Jul 19 '22 22:07 fermoya

I have been able to find a workaround for this (sort off) I made changes to PagerContent. I have a variable @State private var mouseIsOnCards = false on stack I have

let stack = HStack(spacing: interactiveItemSpacing) {
    ForEach(dataDisplayed, id: id) { item in
        Group {
            if self.isInifinitePager && self.isEdgePage(item) {
                EmptyView()
            } else {
                self.content(item.element)
                    .frame(size: self.pageSize)
                    .scaleEffect(self.scale(for: item))
                    .rotation3DEffect((self.isHorizontal ? .zero : Angle(degrees: -90)) - self.scrollDirectionAngle,
                                      axis: (0, 0, 1))
                    .rotation3DEffect(self.angle(for: item),
                                      axis:  self.axis)
                    .opacity(opacity(for: item))
            }
        }
    }
    .offset(x: self.xOffset, y : self.yOffset)
}
.frame(size: size)
.onAppear(perform: monitorScrollWheelEvents)
.onHover { bool in
    withAnimation(.spring()) {
        mouseIsOnCards = bool
    }
}

and finally

private func monitorScrollWheelEvents() {
    #if os(macOS)
    NSEvent.addLocalMonitorForEvents(matching: [.scrollWheel]) { event in
        if mouseIsOnCards {
            if event.phase == .changed {
                let animation = draggingAnimation.animation
                withAnimation(animation) {
                    let x = (event.scrollingDeltaY)
                    self.pagerModel.draggingOffset =  self.draggingOffset + x
                    self.onDraggingChanged?(Double(-self.draggingOffset / self.pageDistance))
                    self.pagerModel.objectWillChange.send()
                }
            }
            if event.phase == .ended {
                onDragGestureEnded()
            }
        }
        return event
    }
    #endif
}

This is preliminary and I have not extensively tested it. That's why I can't PR. You will notice that many precautions implemented in func onDragChanged(with value: DragGesture.Value) are not present. This works for vertical Pager. If you want for horizontal you can use let x = (event.scrollingDeltaX)

iankoex avatar Dec 18 '22 17:12 iankoex

This is the only feature holding me back from using this awesome library. It would be really nice if you somehow managed to add this.

milanvarady avatar Dec 29 '22 09:12 milanvarady