Material Motion Exploring solutions that will empower creators with the tools needed to describe and implement rich, interactive motion on any platform. Edit this page · History
TranslationGestureRecognizer · $._nextOperator translationAddedTo Draggable
Status Interface level Implementation level Library
Stable as of February 21, 2016 L2: Interaction creator L3: Stream creator material-motion
platformsrctests
iOS (Swift) View
translationAddedTo
upstream (TranslationGestureRecognizer)
(Point) downstream

translationAddedTo specification

This is the engineering specification for the MotionObservable operator translationAddedTo that operates on TranslationGestureRecognizer value types.

Overview

Adds the current drag gesture translation to the provided initial position and emits the result.

Example usage:

gesture.translation(addedTo: propertyOf(target).center, in: view)

MVP

Expose translationAddedTo API

This API should only be available for streams emitting TranslationGestureRecognizer values. It should accept an initialPosition readable property and an element within which the translations should be calculated.

extension MotionObservable where T: TranslationGestureRecognizer {
  func translation(addedTo initialPosition: MotionObservable<Point>, in element: Element) -> MotionObservable<Point>
}

Cache the initial position on gesture activation

Update the cache on gesture began or gesture changed if no cache currently exists.

func translation(addedTo initialPosition: MotionObservable<Point>, in element: Element) -> MotionObservable<Point> {
  var cachedInitialPosition: Point?
  return _nextOperator { value, next in
    if value.state == .began || (value.state == .changed && cachedInitialPosition == nil)  {
      cachedInitialPosition = clone(initialPosition._read())
    }
    ...
  }
}

Blow away the cache when the gesture recognizer is inactive

func translation(addedTo initialPosition: MotionObservable<Point>, in element: Element) -> MotionObservable<Point> {
  ...
  return _nextOperator { value, next in
    if value.state == .began || (value.state == .changed && cachedInitialPosition == nil)  {
      ...
    } else if value.state != .began && value.state != .changed {
      cachedInitialPosition = nil
    }
    ...
  }
}

Emit the translationAddedTo initial position

Emit the sum of the cached initial position and the gesture’s translation.

func translation(addedTo initialPosition: MotionObservable<Point>, in element: Element) -> MotionObservable<Point> {
  ...
  return _nextOperator { value, next in
    ...
    if let cachedInitialPosition = cachedInitialPosition {
      let translation = value.translation(in: view)
      next(Point(x: cachedInitialPosition.x + translation.x,
                 y: cachedInitialPosition.y + translation.y))
    }
  }
}