Implement Pan Gesture Interface Using ReactiveCocoa

102 Views Asked by At

Let's say I have a view that I want to be draggable. Using just UIKit I would implement that with a variation of the following logic.

var viewStartY: CGFloat = 0
var panStartY: CGFloat = 0

func handlePan(recognizer: UIPanGestureRecognizer) {
    var location = recognizer.locationInView(someView)

    if recognizer.state == .Began {
        viewStartY = someView.frame.origin.y
        panStartY = location.y
    }
    let delta = location.y - panStartY
    someView.frame.origin.y = viewStartY + delta.y
}

Now I was wondering if there was a way to deal with values like viewStartY that have to be stored when the gesture begins while avoiding side effects. Is there a way to continuously pass them through the pipeline?

1

There are 1 best solutions below

0
On

FlatMap might work for you. Take a stream of beginning gestures, and flatMap a stream of changing gestures over it. This just gives you a stream of changes again, but you can capture the startValue inside the flatMapped function.

Pseudo-code that might explain the technique:

let gestures = recognizer.stream // Depends on your framework

// Filter gesture events by state
let gesture_begans = gestures.filter { $0.state == .Began }
let gesture_changeds = gestures.filter { $0.state == .Changed }

// Take a stream of beginning gestures...
let gesture_deltas = gesture_begans.flatMap { (began) -> in
    let startPoint = began.locationInView(outerView)

    // ... and flatMap into a stream of deltas
    return gesture_changeds.map { (changed) in
        let changedPoint = changed.locationInView(outerView)
        let delta = changedPoint.y - startPoint.y
        return delta
    }
}

gesture_deltas.onValue { y in innerView.frame.origin.y = y }