diff --git a/VDS/Components/CarouselScrollbar/CarouselScrollbar.swift b/VDS/Components/CarouselScrollbar/CarouselScrollbar.swift index ca38bf03..3671c27d 100644 --- a/VDS/Components/CarouselScrollbar/CarouselScrollbar.swift +++ b/VDS/Components/CarouselScrollbar/CarouselScrollbar.swift @@ -112,6 +112,8 @@ open class CarouselScrollbar: View { /// Allows a unique id to be passed into the thumb and track of the thumb(scrubber). open var scrubberId: Int? { didSet { setNeedsUpdate() } } + /// A callback when the scrubber position changes. Passes parameters (position). + open var onScrubberDidChange: ((Int) -> Void)? //-------------------------------------------------- // MARK: - Private Properties @@ -241,29 +243,32 @@ open class CarouselScrollbar: View { // MARK: - Private Methods //-------------------------------------------------- func onMoveBackward() { - thumbView.frame.origin.x = thumbView.frame.origin.x - CGFloat(actualThumbWidth) - updateActiveOverlays() + position = (position ?? 1) - 1 + scrollThumbToPosition(position) } func onMoveForward() { - thumbView.frame.origin.x = thumbView.frame.origin.x + CGFloat(actualThumbWidth) - updateActiveOverlays() + position = (position ?? 1) + 1 + scrollThumbToPosition(position) } - + + // Drag scrollbar thumb to move it to the left or right. + // Upon releases of drag, the scrollbar thumb snaps to the closest full position and the scrollbar returns to original size without delay. @objc func onScrubberDrag(_ sender: UIPanGestureRecognizer) { let translation = sender.translation(in: thumbView) if sender.state == UIGestureRecognizer.State.began { trayOriginalCenter = thumbView.center } else if sender.state == UIGestureRecognizer.State.changed { - let movePositions = Int (ceil (Double(translation.x) / Double(actualThumbWidth))) - setThumb(at: (position ?? 1) + movePositions) + let draggedPositions = Int (ceil (Double(translation.x) / Double(actualThumbWidth))) + setThumb(at: (position ?? 1) + draggedPositions) } else if sender.state == UIGestureRecognizer.State.cancelled || sender.state == UIGestureRecognizer.State.ended { - let movePositions = Int (ceil (Double(translation.x) / Double(actualThumbWidth))) - position = (position ?? 1) + movePositions + let draggedPositions = Int (ceil (Double(translation.x) / Double(actualThumbWidth))) + position = (((position ?? 1) + draggedPositions) < 1) ? 1 : ((position ?? 1) + draggedPositions) } } + // Move the scrollbar thumb to the left while tapping on the left side of the scrubber. @objc func onThumbTouchStart(_ gesture: UILongPressGestureRecognizer) { if gesture.state == .began { leftActiveOverlay.backgroundColor = activeOverlayColorConfiguration.getColor(self) @@ -274,12 +279,11 @@ open class CarouselScrollbar: View { } else if gesture.state == .ended { leftActiveOverlay.backgroundColor = .clear leftActiveOverlay.layer.opacity = defaultOpacity - DispatchQueue.main.asyncAfter(deadline: .now() + .milliseconds(100)) { [weak self] in - self?.onMoveBackward() - } + self.onMoveBackward() } } + // Move the scrollbar thumb to the right while tapping on the right side of the scrubber. @objc func onThumbTouchEnd(_ gesture: UILongPressGestureRecognizer) { if gesture.state == .began { rightActiveOverlay.backgroundColor = activeOverlayColorConfiguration.getColor(self) @@ -290,12 +294,12 @@ open class CarouselScrollbar: View { } else if gesture.state == .ended { rightActiveOverlay.backgroundColor = .clear rightActiveOverlay.layer.opacity = defaultOpacity - DispatchQueue.main.asyncAfter(deadline: .now() + .milliseconds(100)) { [weak self] in - self?.onMoveForward() - } + self.onMoveForward() } } + // Minimum thumb width applied + // Incomplete set moves a shorter distance than the standard increment value. private func setThumbWidth() { let width = (Float(trackViewWidth) / Float(numberOfSlides ?? 1)) * Float(_selectedLayout.value) actualThumbWidth = (width > Float(trackViewWidth)) ? Float(trackViewWidth) : width @@ -306,6 +310,7 @@ open class CarouselScrollbar: View { updateActiveOverlays() } + // Update active overlay frames according to thumb position. private func updateActiveOverlays() { // adjusting thumb position if it goes beyond trackView. let thumbPosition = thumbView.frame.origin.x + thumbView.frame.size.width @@ -331,6 +336,7 @@ open class CarouselScrollbar: View { private func scrollThumbToPosition(_ position: Int?) { DispatchQueue.main.asyncAfter(deadline: .now() + .milliseconds(100)) { [weak self] in self?.setThumb(at: position) + self?.onScrubberDidChange?(position ?? 1) } }