0

I have a method that drops down a UIView. That works fine. How would I go about having it slide back up when the button is touched a second time?

I also need to deactivate it somehow so that it doesn't repeat the animation if it's already displayed.

- (void)slideDownTableView {

    self.tableViewCities = [[UITableView alloc] initWithFrame:self.view.bounds style:UITableViewStylePlain];

    self.tableViewCities.frame = CGRectMake(0,0,300,180);
    self.tableViewCities.autoresizingMask = ( UIViewAutoresizingFlexibleHeight | UIViewAutoresizingFlexibleWidth );
    self.tableViewCities.dataSource = self;
    self.tableViewCities.delegate = self;
    self.tableViewCities.backgroundColor = [UIColor whiteColor];


    UIView *myview=[[UIView alloc] initWithFrame: CGRectMake(10, 0,300,180)];
    myview.backgroundColor=[UIColor redColor];

    [myview addSubview:self.tableViewCities];

    [self.view addSubview:myview];
    myview.frame = CGRectMake(10, 0,300,-180); // offscreen

        [UIView animateWithDuration:0.5
                         animations:^{
                             myview.frame = CGRectMake(10, 0,300,180); // final location move
                         }];
}
user2588945
  • 1,681
  • 6
  • 25
  • 38
  • 2
    take a bool varable and check weather opened or not and take a condtion and animation based on that value. – Balu Sep 21 '13 at 10:16
  • http://stackoverflow.com/questions/16303010/how-to-stop-and-reverse-a-uiview-animation – yunas Sep 21 '13 at 10:20

5 Answers5

2

iOS provides autoreverse property by which animation reverses automatically.

UIViewAnimationOptionAutoreverse will give you an effect as the animation reverses .

   [UIView animateWithDuration:0.5
                          delay:0.0
                        options:UIViewAnimationOptionAutoreverse   
                     animations:^{
                         // do whatever animation you want, e.g.,

                         someView.frame = someFrame1;
                     }
                     completion:NULL];
AtWork
  • 1,283
  • 1
  • 14
  • 34
1

Using BeginFromCurrentState option worked for me.

Ali Momen Sani
  • 840
  • 2
  • 11
  • 26
0
if(!enabled){
            [UIView animateWithDuration:0.4 delay:0.0 options:UIViewAnimationTransitionCurlUp
                             animations:^{
              myview.frame = CGRectMake(10, 0,300,180);

     }
      completion:nil];
       enabled=YES;

}
else{
     [UIView animateWithDuration:0.4 delay:0.0 options:UIViewAnimationTransitionCurlUp
                             animations:^{
              myview.frame = CGRectMake(10, 0,300,-180);

     }
      completion:nil];
       enabled=NO;
}
Balu
  • 8,470
  • 2
  • 24
  • 41
0

With a simple BOOL to store the current state of the sliding UIView you can achieve this.

The initial state is not visible if I understand well? So initially the BOOL citiesVisible is set to N0, then the button's action check its value, and performs a different animation accordingly. Simple.

Finally, I also disable the button during the animation to prevent the user to trigger a second animation while a first one is already performing.

I rewrote a bit your code to follow some best practices, and improve readability/maintainability:

  • Setting up the views beforehand because the button's action responsibility shouldn't be to setup the views, but only to animate them.
  • Changed the signature of the target action, that's my personal style guide to state in the sender's name and the ControlEvent, it makes it more tidy when you have multiple buttons/actions ;). Also per Apple guidelines, methods receiving actions should have one "id" parameter, the sender.
  • Store the frames in variables (you could also have them as #define, that'd be even better I think), so you don't have to hard-code them twice, it reduces the risk of breaking the animation by having a view sliding to different positions...

Code update:

@interface ViewController ()

@property (nonatomic, strong) UIButton *showCitiesButton;

@property (nonatomic, strong) CGRect citiesInitialFrame;
@property (nonatomic, strong) CGRect citiesVisibleFrame;

@property (nonatomic, strong) UITableView *tableViewCities;
@property (nonatomic, strong) UIView *citiesContainer;

@property (nonatomic, strong) BOOL citiesVisible;

@end

@implementation ViewController

- (void)viewDidLoad
{
    [super viewDidLoad];

    // Setting up the cities view
    self.citiesInitialFrame = CGRectMake(10, -180, 300, 180);
    self.citiesVisibleFrame = CGRectMake(10, 0, 300, 180);

    self.tableViewCities = [[UITableView alloc] init ...];
    self.citiesContainer = [[UIView alloc] init ...];

    // ...

    self.citiesVisible = NO;

    [self.showCitiesButton addTarget:self
                              action:@selector(showCitiesButtonDidTouchUpInside:)
                    forControlEvents:UIControlEventTouchUpInside];
}

- (void)showCitiesButtonDidTouchUpInside:(id)sender
{
    [self.showCitiesButton setEnabled:NO];
    if (self.citiesVisible)
    {
        // Cities view is visible, sliding it out of the screen
        [UIView animateWithDuration:0.5
                         animations:^{
                             self.citiesContainer.frame = self.citiesInitialFrame;
                         } completion:^(BOOL finished) {
                             self.citiesVisible = NO;
                             [self.showCitiesButton setEnabled:YES];
                         }];
    }
    else
    {
        // Cities view is not visible, sliding it in
        [UIView animateWithDuration:0.5
                         animations:^{
                             self.citiesContainer.frame = self.citiesVisibleFrame;
                         } completion:^(BOOL finished) {
                             self.citiesVisible = YES;
                             [self.showCitiesButton setEnabled:YES];
                         }];
    }

}

@end
Jean-Étienne
  • 145
  • 2
  • 9
0

You can reverse UIView animation with this code:

if (isMarked) {

    [UIView animateWithDuration:3
                          delay:0
                        options:UIViewAnimationOptionBeginFromCurrentState
                     animations:(void (^)(void)) ^{
                         self.transform=CGAffineTransformMakeScale(1.1, 1.1);
                     }
                     completion:nil];

} else {

    [UIView animateWithDuration:3
                          delay:0
                        options:UIViewAnimationOptionBeginFromCurrentState
                     animations:(void (^)(void)) ^{
                         self.transform=CGAffineTransformIdentity;
                     }
                     completion:nil];
}
Max Niagolov
  • 684
  • 9
  • 26