views:

193

answers:

2

Hello!

I've been working on a new app and was really hoping to implement a swipe to reveal more options menu inside my application. I've searched and searched, but it seems no one else has successfully made it work (aside from Loren). What I'm trying to do is swipe the cell, and simultaneously use CABasicAnimation to push it to x: 320, and add a subview below this that would have the buttons etc.. I'm using willBeginEditing to detect the swipe to avoid subclassing. Here's the code:

- (void)tableView:(UITableView *)tableView willBeginEditingRowAtIndexPath:(NSIndexPath *)indexPath {

 UITableViewCell *cell = [tableView cellForRowAtIndexPath:indexPath];

 CABasicAnimation *theAnimation;          

 theAnimation=[CABasicAnimation animationWithKeyPath:@"transform.translation.x"];

 theAnimation.duration=0.0;

 theAnimation.repeatCount=0;

 theAnimation.autoreverses=NO;

 theAnimation.removedOnCompletion = NO;

 theAnimation.fillMode = kCAFillModeForwards;

 theAnimation.fromValue=[NSNumber numberWithFloat:0];

 theAnimation.toValue=[NSNumber numberWithFloat:+320];

 [cell.layer addAnimation:theAnimation forKey:@"animateLayer"];

 CGRect frame = CGRectMake(0, 59 * indexPath.row, 320, 59);

 UIView *menu = [[[UIView alloc] initWithFrame:frame] autorelease];


 NSString *path = [NSString stringWithFormat:@"%@%@",

                       [[NSBundle mainBundle] resourcePath],

                       @"/flick.wav"];



 SystemSoundID soundID;

 NSURL *filePath = [NSURL fileURLWithPath:path isDirectory:NO];

 AudioServicesCreateSystemSoundID((CFURLRef)filePath, &soundID);

 AudioServicesPlaySystemSound(soundID);

 self.menu.backgroundColor = [UIColor colorWithPatternImage:[UIImage imageNamed:@"dots.png"]];

 [self.view addSubview:menu];

 [self.view sendSubviewToBack:menu];

 }



- (void)animationDidStop:(NSString*)animationID finished:(BOOL)finished context:(void     *)context 

{

   // Release

   [self release];

}


 #pragma mark - Swipe Menu II



- (void)scrollViewDidScroll:(UIScrollView *)tableView {

     UITableViewCell *cell = [tableView cellForRowAtIndexPath:nil];

     CABasicAnimation *theAnimation;          

     theAnimation=[CABasicAnimation animationWithKeyPath:@"transform.translation.x"];

     theAnimation.duration=0.2;

 theAnimation.repeatCount=0;

 theAnimation.autoreverses=NO;

 theAnimation.fromValue=[NSNumber numberWithFloat:320];

 theAnimation.toValue=[NSNumber numberWithFloat:0]

 ;

 [cell.layer addAnimation:theAnimation forKey:@"animateLayer"];

 }

The problem is the sliding back of the cell - I want to do it when any touch outside the menu view is received, but because it is a scrollView, I can't. The ScrollViewdidScroll Method only animates the cell back to its normal place once it is scrolled of the viewport. (As in, under the NavigationBar or object that obscures it) The last key issue is the ability to detect if a menu is already visible or active and a cell is already off of the screen, slide the cell back to its original position, remove the menu view, and then slide the other cell out and add the menu.

I would like to be the first beside Loren to implement this as so many others have tried, especially on StackOverflow.

I apologize for the poor formatting in the code.

Thanks in advance, Kolin

A: 

Loren's implementation has a fatal flaw, which is if you swipe on a cell, then scroll the table, you cannot re-swipe the same cell until you swipe a different cell. I believe this is because the tableview believes the cell is still being edited until you try and "edit" another cell.

You may want to investigate doing something else instead, like using a UISwipeGestureRecognizer attached to the cell to detect the swipe.

I can think of 2 approaches to try and detect taps outside of the cell as well. The first is to subclass UIApplication and override -sendEvent:. You can use this to detect the tap event and dismiss the cell "editing". The main problem here is giving the UIApplication subclass knowledge about your cell. The second approach is to slap a custom UIView subclass over the entire screen and in -hitTest:withEvent: you can test to see if the touch belongs to the area over your cell. If it doesn't, dismiss the cell "editing". In both cases, return nil to allow the event to proceed to the underlying views (and don't forget to remove this overlay view after the event happens). You may also want to test the UIEvent to make sure it contains a new touch before dismissing the cell.

Kevin Ballard
Thanks for your answer and explaining it! I'm going to look into Tom's code, as it seems to fix Tweetie/Twitter's issue.
Kolin Krewinkel
+2  A: 

I've actually made this work quite nicely, you can check out the project here: http://www.thermoglobalnuclearwar.com/opensource/

It also overcomes the problem in Tweetie where you cannot swipe the same cell twice without first swiping something else.

If you make any constructive changes, or need any help, let me know!

Tom Irving
Thanks for the code! I'll take a look at it and see what I can do with it!
Kolin Krewinkel
Not a problem :)
Tom Irving
Would you mind helping me implement it into my app? The configuration I have is different and I can't seem to get it to work.
Kolin Krewinkel
Yeah sure thing, there's a "contact me" link on the page I linked in my answer, you can reach me there.
Tom Irving
@Tom Irving: i'm looking for how to make Swipe to Reveal Menu like Reeder. I thinks its simular with your TISwipeableTableView. Can you tell me how to make Swipe to Reveal Menu like Reeder :(. Thanks :)
leduchuy89vn
Yeah I emailed you, I haven't seen the Reeder app.
Tom Irving
@Tom Irving: I want to add UIButton to your ExampleCell. Can you tell me how can i do it :)
leduchuy89vn
A bunch of UIButtons are actually included in the ExampleCell.m file...
Tom Irving