Search code examples
iphoneobjective-cxcodecocoa-touchcore-animation

UITableViewCell Panning to reveal options: Animated


So I have a very good implementation of panning on a tableview cell. I basically use panGestureRecognizer and move the cell off screen, and show another view below the tableViewCell. This is working fine. When I pan on the tableViewCell, I basically reveal 5 buttons underneath.

My goal is to animate the 5 buttons as the tableviewcell is moving. For example,


| 1 | 2 | 3 | 4 | 5|

If I am swiping, and moving the cell right and I am cross button 1, I will animate button popping out and become visible to the user. If I am crossing 2, then 2 will animate popping out, and become visible to the user. And when I am in button 5, all buttons are already popped and ready for user actions.

I am doing this with

    //Scale Animation
    CABasicAnimation *scaleAnim = [CABasicAnimation animationWithKeyPath:@"transform"];
    scaleAnim.duration = 0.3;
    scaleAnim.toValue = [NSValue valueWithCATransform3D:CATransform3DIdentity];
    scaleAnim.fromValue = [NSValue valueWithCATransform3D:CATransform3DMakeScale(0.1,0.1, 1.0)];
    scaleAnim.removedOnCompletion = YES;
    [view.layer addAnimation:scaleAnim forKey:nil];

**

My goal :

**

So when I am in the middle of a panning gesture, and I decide to close it ( move to the left), the buttons should pop-in, and become unavailable to the user.

Also, as I move the cell the button should gradually scale up, and become available to the user. So I will essentially need to pass the cell's origin and use some math to compute the scale for the buttons based on the button's origin and width (fairly straight-forward).

if (CGRectIntersectsRect(button.frame, self.movingCell.frame))
{
    CGFloat xScale = cellTranslation - xOriginForButton;
    [self popOutAnimate:button withScale:xScale/ (xWidthForButtons + xSpaceBetweenButtons)];
}

But the problem comes up when I move the cell really fast, the views don't get all the changes in cell's movement and they are stuck in a half animated state.

I have a feeling that I am not grasping the logic right. The whole implementation is similar to the Sparrow iphone mail app. When you pan on the cell, the buttons reveal with animation as the cell is moved. For those who have not used sparrow. You can see the panning gesture in 1:25 https://www.youtube.com/watch?v=XLX6XV0SbWI&t=1m25s

Is the logic correct? Am I missing something?

Any help is much appreciated.


Solution

  • After working on this using several different ways, I ended up with a solution for this, and I am typing it below.

    Algorithm:

    The principal to swiping or panning a tableViewCell is straight-forward. The algorithm for popping out buttons underneath the cell is based on the current location of the cell in comparison to the position of the buttons. There are several ways to go about this, and the one used in the following example is _NOT_THE_MOST_OPTIMAL_ one given the complications that arise when we reorder the buttons. (i.e. if the buttons are re-ordered, the algorithm will fail).

    Lets look at the case of the best solution to this problem.

    1. Perform a hit_test using (CGRectIntersects(rect1, rect2)to find out where the cell meets any of the buttons. ==> This would be the most ideal solution as replacing or interchanging buttons will still work fine. But We cannot use this approach as hit_test will fail when the cell is moved quickly. This will leave the buttons in a very improper state.

    2. Use the frame of the buttons directly based on the translation and scale them up. ===> We cannot use the frame of the buttons for any scenario because as we scale them, (x,y,size,width) vary drastically

    3. Cache the button frames before animation and use them for scaling them. ===> Caching them might work for certain situations, but we will need to update them very regularly, and also make sure to cache them after ORIENTATION_CHANGE. This will again be a pain as button frames after orientation change also very drastically (Refer to pt 2).

    Working:

    So if we are going to be animating all the buttons underneath the cell, then you will have only one regionOfAnimation. If you have a set of portion with static buttons, and a set of buttons that need to be animated, then we have 2 regions - the one region with staticButtons, and the other regionOfAnimation.

    These values for the region were computed based on the position of the animated region (as set in IB). We again split the regionOfAnimation EVENLY based on the number of buttons present, and as the cell moves across each split, we animate the buttons beneath it.

    |    Region of Static Buttons   |  Region of Animation  |
    ---------------------------------------------------------
    | Static Button | Static Button |  1 |  2 |  3 |  4 |  5|
    ---------------------------------------------------------
    |                                       
    |              ===>  CELL MOVES ====>               
    |   
    ---------------------------------------------------------
    

    The advantages of this method:

    1. Performance is better than hit_test (much needed break)
    2. Buttons will always animate properly since we dont access their frames for calculations

    Dis-advantages:

    1. The region of static buttons, and region of animation must be calculated before hand for both orientations.
    2. If the buttons are interchanged, the algorithm needs to be updated to reflect the new changes.