stable scrolling and drag
parent
09ffa5f8e2
commit
3af58e417f
|
@ -101,8 +101,10 @@ class ShowTitle: NSObject, ObservableObject {
|
|||
@Published var chapVisible = false
|
||||
}
|
||||
|
||||
|
||||
struct Pane: View {
|
||||
@ObservedObject var paneConnector: PaneConnector
|
||||
@ObservedObject var scrollDelegate: ScrollDelegate
|
||||
@StateObject var showTitle = ShowTitle()
|
||||
|
||||
// @State var chapVisible = false
|
||||
|
@ -202,9 +204,8 @@ struct Pane: View {
|
|||
let reactive = self.refresh
|
||||
}
|
||||
|
||||
// if self.paneConnector != nil {
|
||||
// let reactive = self.paneConnector
|
||||
// }
|
||||
scrollView.canCancelContentTouches = false
|
||||
scrollView.delegate = scrollDelegate
|
||||
|
||||
DispatchQueue.main.async {
|
||||
if paneConnector.setScrollOffset != nil {
|
||||
|
|
|
@ -215,6 +215,7 @@ func makeVerseView(seg: SegDenorm) -> some View {
|
|||
}
|
||||
|
||||
class PaneConnector: NSObject, ObservableObject {
|
||||
|
||||
var showOverlay: Bool = false
|
||||
@Published var refresh: Bool = false
|
||||
@Published var vertSep = CGFloat(20)
|
||||
|
@ -225,9 +226,27 @@ class PaneConnector: NSObject, ObservableObject {
|
|||
@Published var scrollOffset = CGFloat()
|
||||
@Published var hasMoved = false
|
||||
var setScrollOffset: CGFloat?
|
||||
@Published var disableScroll = false
|
||||
|
||||
|
||||
}
|
||||
|
||||
class ScrollDelegate: NSObject, ObservableObject, UIScrollViewDelegate {
|
||||
@Published var isScrolling = false
|
||||
|
||||
func scrollViewWillBeginDragging(_: UIScrollView) {
|
||||
print("pop started scroll")
|
||||
isScrolling.toggle()
|
||||
}
|
||||
|
||||
func scrollViewDidEndDragging(_: UIScrollView, willDecelerate _: Bool) {
|
||||
print("pop ended scroll")
|
||||
isScrolling.toggle()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
struct ContentView: View {
|
||||
// this is for the whole view swiping
|
||||
@State var mainSwipe = CGSize.zero
|
||||
|
@ -236,6 +255,7 @@ struct ContentView: View {
|
|||
@State var selection = 0
|
||||
|
||||
@StateObject var paneConnector = PaneConnector()
|
||||
@StateObject var scrollDelegate = ScrollDelegate()
|
||||
|
||||
@State var refresh: Bool = false
|
||||
|
||||
|
@ -248,6 +268,8 @@ struct ContentView: View {
|
|||
|
||||
@State var dragOffset = CGFloat(0)
|
||||
|
||||
@GestureState var dragGestureActive = CGSize.zero
|
||||
|
||||
enum SwipeStartState {
|
||||
case center
|
||||
case right
|
||||
|
@ -271,10 +293,13 @@ struct ContentView: View {
|
|||
init() {
|
||||
UITableView.appearance().backgroundColor = UIColor(Color(red: 0.2, green: 0.2, blue: 0.2))
|
||||
_selectedRibbon = Query(SelectedRibbonRequest())
|
||||
|
||||
}
|
||||
|
||||
|
||||
var body: some View {
|
||||
|
||||
|
||||
var fontSize = CGFloat(15)
|
||||
var scale = 0.65
|
||||
var height = CGFloat(50)
|
||||
|
@ -327,6 +352,7 @@ struct ContentView: View {
|
|||
// Top pane
|
||||
|
||||
Pane(paneConnector: paneConnector,
|
||||
scrollDelegate: scrollDelegate,
|
||||
selectedRibbon: selectedRibbon,
|
||||
width: geometry.size.width - 15,
|
||||
height: geometry.size.height + 20,
|
||||
|
@ -340,7 +366,7 @@ struct ContentView: View {
|
|||
// .onChanged { gesture in
|
||||
// paneConnector.vertSep = paneConnector.vertSep - gesture.translation.height
|
||||
// }
|
||||
// )
|
||||
//
|
||||
|
||||
// // Bottom pane
|
||||
// ScrollViewReader { _ in
|
||||
|
@ -372,9 +398,14 @@ struct ContentView: View {
|
|||
.offset(x: 20, y: 0)
|
||||
.offset(x: pulledOut.width)
|
||||
.offset(x: mainSwipe.width)
|
||||
.gesture(
|
||||
DragGesture()
|
||||
.highPriorityGesture(
|
||||
DragGesture(minimumDistance: 30)
|
||||
.updating($dragGestureActive) { value, state, _ in
|
||||
print("pop here")
|
||||
state = value.translation
|
||||
}
|
||||
.onChanged { value in
|
||||
print("pop changed")
|
||||
// Calculate the offset
|
||||
|
||||
let margin = CGFloat(30)
|
||||
|
@ -398,44 +429,40 @@ struct ContentView: View {
|
|||
startSwipeDir = .left
|
||||
}
|
||||
|
||||
|
||||
// Apply resistance if out of bounds
|
||||
var maxOffsetRight: CGFloat = 110
|
||||
var maxOffsetLeft: CGFloat = 200
|
||||
var maxOffsetRight: CGFloat = 150
|
||||
var maxOffsetLeft: CGFloat = -200
|
||||
|
||||
// if startSwipeState == .right {
|
||||
// if startSwipeDir == .right {
|
||||
// maxOffsetRight = .zero
|
||||
// maxOffsetLeft = .zero
|
||||
// } else if startSwipeDir == .left {
|
||||
// maxOffsetRight = CGFloat(110)
|
||||
// maxOffsetLeft = CGFloat(-30)
|
||||
// }
|
||||
// } else if startSwipeState == .left {
|
||||
|
||||
if startSwipeState == .right {
|
||||
if startSwipeDir == .right {
|
||||
maxOffsetRight = .zero
|
||||
maxOffsetLeft = .zero
|
||||
} else if startSwipeDir == .left {
|
||||
maxOffsetRight = CGFloat(110)
|
||||
maxOffsetLeft = CGFloat(-30)
|
||||
}
|
||||
} else if startSwipeState == .left {
|
||||
// if startSwipeDir == .left {
|
||||
// maxOffsetLeft = .zero
|
||||
// maxOffsetRight = .zero
|
||||
// } else if startSwipeDir == .right {
|
||||
// maxOffsetLeft = CGFloat(200)
|
||||
// maxOffsetRight = CGFloat(10)
|
||||
// }
|
||||
// }
|
||||
|
||||
if startSwipeDir == .left {
|
||||
maxOffsetLeft = .zero
|
||||
maxOffsetRight = .zero
|
||||
} else if startSwipeDir == .right {
|
||||
maxOffsetLeft = CGFloat(200)
|
||||
maxOffsetRight = CGFloat(10)
|
||||
}
|
||||
}
|
||||
|
||||
if newOffset + pulledOut.width < -maxOffsetLeft {
|
||||
if startSwipeState == .right && startSwipeDir == .left {
|
||||
newOffset = -maxOffsetLeft + rubberBandEffect(newOffset + maxOffsetLeft) - pulledOut.width
|
||||
} else {
|
||||
newOffset = -maxOffsetLeft + rubberBandEffect(newOffset + maxOffsetLeft)
|
||||
}
|
||||
|
||||
} else if newOffset + pulledOut.width > maxOffsetRight {
|
||||
if startSwipeState == .left, startSwipeDir == .right {
|
||||
newOffset = maxOffsetRight + rubberBandEffect(newOffset - maxOffsetRight) - pulledOut.width
|
||||
} else {
|
||||
if newOffset > maxOffsetRight, pulledOut.width == 0 {
|
||||
// newOffset = maxOffsetRight + rubberBandEffect(newOffset)
|
||||
newOffset = maxOffsetRight + rubberBandEffect(newOffset - maxOffsetRight)
|
||||
}
|
||||
|
||||
if newOffset > 0, pulledOut.width > 0 {
|
||||
newOffset = rubberBandEffect(newOffset)
|
||||
}
|
||||
|
||||
if newOffset < maxOffsetLeft, pulledOut.width == 0 {
|
||||
newOffset = maxOffsetLeft + rubberBandEffect(newOffset)
|
||||
}
|
||||
|
||||
self.mainSwipe.width = newOffset
|
||||
|
@ -443,17 +470,34 @@ struct ContentView: View {
|
|||
// dragOffset is what is used to make the text be readable
|
||||
// with the right pane being visible
|
||||
|
||||
// if mainSwipe.width < -margin && pulledOut.width <= 0 {
|
||||
|
||||
if mainSwipe.width < -margin && pulledOut.width <= 0 {
|
||||
if mainSwipe.width < -margin, pulledOut.width <= 0 {
|
||||
dragOffset = margin + mainSwipe.width + pulledOut.width
|
||||
}
|
||||
|
||||
if mainSwipe.width > 0 && pulledOut.width < 0 {
|
||||
if mainSwipe.width > 0, pulledOut.width < 0 {
|
||||
dragOffset = margin + mainSwipe.width + pulledOut.width
|
||||
}
|
||||
}
|
||||
.onEnded { _ in
|
||||
onDragEnded()
|
||||
}
|
||||
)
|
||||
.onChange(of: scrollDelegate.isScrolling) { value in
|
||||
print ("pop reset change")
|
||||
// if scrollDelegate.isScrolling == true {
|
||||
Task {
|
||||
mainSwipe.width = 0
|
||||
}
|
||||
// }
|
||||
}
|
||||
}
|
||||
}
|
||||
.background(Color(red: 0.1, green: 0.1, blue: 0.1))
|
||||
}
|
||||
|
||||
func onDragEnded() {
|
||||
print("pop ended")
|
||||
paneConnector.disableScroll = false
|
||||
var finalSwipe = CGFloat(0)
|
||||
let swipeLeftFinal = CGFloat(-200)
|
||||
let swipeRightFinal = CGFloat(110)
|
||||
|
@ -477,7 +521,6 @@ struct ContentView: View {
|
|||
finalSwipe = swipeRightFinal
|
||||
}
|
||||
} else if startSwipeState == .left {
|
||||
|
||||
if startSwipeDir == .left {
|
||||
finalSwipe = swipeLeftFinal
|
||||
setDragOffset = margin + swipeLeftFinal
|
||||
|
@ -510,16 +553,46 @@ struct ContentView: View {
|
|||
mainSwipe = .zero
|
||||
}
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
.background(Color(red: 0.1, green: 0.1, blue: 0.1))
|
||||
}
|
||||
|
||||
|
||||
|
||||
// let hackyPinch = MagnificationGesture(minimumScaleDelta: 0.0)
|
||||
// .onChanged({ delta in
|
||||
// onDragEnded()
|
||||
// })
|
||||
// .onEnded({ delta in
|
||||
// onDragEnded()
|
||||
// })
|
||||
|
||||
// let hackyRotation = RotationGesture(minimumAngleDelta: Angle(degrees: 0.0))
|
||||
// .onChanged({ delta in
|
||||
// onDragEnded()
|
||||
// })
|
||||
// .onEnded({ delta in
|
||||
// onDragEnded()
|
||||
// })
|
||||
|
||||
// let hackyPress = LongPressGesture(minimumDuration: 0.0, maximumDistance: 0.0)
|
||||
// .onChanged({ _ in
|
||||
// onDragEnded()
|
||||
// })
|
||||
// .onEnded({ delta in
|
||||
// onDragEnded()
|
||||
// })
|
||||
|
||||
|
||||
|
||||
func handleVisibilityChanged2(_: String, change _: VisibilityChange, tracker _: VisibilityTracker<String>) {}
|
||||
|
||||
func rubberBandEffect(_ offset: CGFloat) -> CGFloat {
|
||||
let resistance: CGFloat = 0.55
|
||||
return resistance * pow(abs(offset), 0.7) * (offset < 0 ? -1 : 1)
|
||||
let resistance: CGFloat = 0.05
|
||||
return 4 * log(offset + 1)
|
||||
// return resistance * pow(abs(offset), 1) * (offset < 0 ? -1 : 1)
|
||||
}
|
||||
|
||||
private func dragCancelled() {
|
||||
print("pop dragCancelled")
|
||||
mainSwipe = .zero
|
||||
}
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue