Skip to content

Instantly share code, notes, and snippets.

@jbender
Created February 11, 2016 16:38
Show Gist options
  • Save jbender/fc7f2d997424014d9477 to your computer and use it in GitHub Desktop.
Save jbender/fc7f2d997424014d9477 to your computer and use it in GitHub Desktop.
Example RubyMotion Swipable Cell module
module SwipeableCell
ANIMATION_DURATION = 0.2
MAX_TRANSITION_ALPHA = 0.5
SWIPE_THRESHOLD = 110
LONG_SWIPE_THRESHOLD = SWIPE_THRESHOLD + 80
FADE_IN_DISTANCE = SWIPE_THRESHOLD
def gestureRecognizer(recognizer,
shouldRecognizeSimultaneouslyWithGestureRecognizer: other_recognizer)
return true unless recognizer.is_a? UIPanGestureRecognizer
# Allow other recognizers to see vertical panning
Gesture.panning_vertically?(recognizer, content_view)
end
def gestureRecognizerShouldBegin(recognizer)
return true unless recognizer.is_a? UIPanGestureRecognizer
# Only respond to events if they're panning side to side
Gesture.panning_horizontally?(recognizer, content_view)
end
def on_pan(recognizer)
current_location = Gesture.location(recognizer, content_view)
case recognizer.state
when UIGestureRecognizerStateBegan
@pan_gesture_start = current_location
when UIGestureRecognizerStateChanged
handle_panning horizontal_movement(current_location)
when UIGestureRecognizerStateEnded, UIGestureRecognizerStateCancelled
handle_gesture_end horizontal_movement(current_location)
end
end
# rubocop:disable Style/HashSyntax
def slide_card(location, delay = 0, &completion)
UIView.animateWithDuration(ANIMATION_DURATION,
delay: delay,
options: UIViewAnimationOptionCurveLinear &&
UIViewAnimationOptionAllowUserInteraction,
animations: -> { move_card_horizontally(location) },
completion: -> (_) { completion.call if completion }
)
end
# rubocop:enable Style/HashSyntax
def slide_card_to_center(&callback)
slide_card(0, &callback)
end
def slide_card_off_screen(direction = :rtl, &callback)
raise 'Invalid direction' unless [:rtl, :ltr].include? direction
screen_size = content_view.frame.size.width
location = direction == :rtl ? -screen_size : screen_size
slide_card(location, &callback)
table_screen.swiped_cell = self
end
def move_card_horizontally(location)
move_content_to(location)
reapply_layout
end
def hidden_icons
{}
end
def icon_layout
raise 'Cell must define icon_layout'
end
def move_content_to(location)
raise 'Cell must define move_content_to'
end
def handle_panning(delta)
slide_card(-delta)
update_icons(delta)
end
private
def alpha_from_delta(delta)
return 1 if delta.abs >= FADE_IN_DISTANCE
(delta.abs / FADE_IN_DISTANCE) * MAX_TRANSITION_ALPHA
end
# rubocop:disable Style/HashSyntax
def connect_to_pan_recognizer
pan_recognizer =
UIPanGestureRecognizer.alloc.initWithTarget self, action: 'on_pan:'
pan_recognizer.delegate = self
layout.view.addGestureRecognizer pan_recognizer
end
# rubocop:enable Style/HashSyntax
# Right -> Left = Positive delta
# Left -> Right = Negative delta
def delta_to_direction(delta)
delta > 0 ? :rtl : :ltr
end
def handle_gesture_end(delta)
end
def hide_icon(icon_id)
icon_layout.get(icon_id).alpha = 0
end
def hide_icons(&callback)
hidden_icons.values.map { |icon| icon[:object_id] }.each do |icon_id|
# rubocop:disable Style/HashSyntax
UIView.animateWithDuration(ANIMATION_DURATION,
animations: -> { hide_icon(icon_id) }
)
# rubocop:enable Style/HashSyntax
end
rmq.app.delay(ANIMATION_DURATION) { callback.call if callback }
end
def hide_inverse_icon(inverse_icon_hash)
hide_icon inverse_icon_hash[:object_id]
end
def horizontal_movement(current_location)
@pan_gesture_start.x - current_location.x
end
def icon_image_name(delta)
icon_options = hidden_icons[delta_to_direction(delta)]
return unless icon_options
return icon_options[:default_image] if delta.abs < SWIPE_THRESHOLD
if delta.abs < LONG_SWIPE_THRESHOLD || !icon_options[:long_swipe_image]
return icon_options[:short_swipe_image]
end
icon_options[:long_swipe_image]
end
def reapply_layout
content_view.layoutIfNeeded
end
def screen_size
content_view.frame.size.width
end
def show_revealing_icon(icon_hash, delta)
icon = icon_layout.get(icon_hash[:object_id])
icon.alpha = alpha_from_delta(delta)
icon.image =
rmq.image.resource("dashboard/#{icon_image_name(delta)}")
end
def update_icons(delta)
direction = delta_to_direction(delta)
icon_hash = hidden_icons[direction]
inverse_icon_hash = hidden_icons[direction == :rtl ? :ltr : :rtl]
show_revealing_icon(icon_hash, delta) if icon_hash
return unless inverse_icon_hash
hide_inverse_icon(inverse_icon_hash)
end
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment