14

I'm trying to animate a tableview's offset down, then in the completion block would move it back up. But my code is not doing anything in the completion block:

-(void)viewDidAppear:(BOOL)animated {
    if (TRUE) {
         NSLog(@"animating table view");

        [UIView animateWithDuration:.25
                         animations:^{
                             self.tableView.contentOffset = CGPointMake(self.tableView.contentOffset.x, self.tableView.contentOffset.y - 60);
                         }
                         completion:^(BOOL finished){
                             NSLog(@"completion block");
                         }];
    }
}

"completion block" never gets outputted... any ideas?

EDIT:

Ok, so it has something to do with my UIREfreshControl:

- (void)viewDidLoad
{
    [super viewDidLoad];

    if (TRUE) {
        UIRefreshControl *refresh = [[UIRefreshControl alloc] init];
        refresh.attributedTitle = [[NSAttributedString alloc] initWithString:@"Pull to Refresh"];
        [refresh addTarget:self action:@selector(refreshTableView:) forControlEvents:UIControlEventValueChanged];

        [self setRefreshControl:refresh];
    }
}

When the refresh controll is added, it won't fire off the completion block. if i dont' add the control, it works as intended.

EDIT 2:

K, so if i scroll the table view, the completion block is then fired:

2013-02-15 13:37:06.266 [1922:14003] animating table view
2013-02-15 13:37:14.782 [1922:14003] completion block

the code as written should log "completion block" right after "animating table view", but it has a 8 second delay cause thats when i scrolled the table view myself.

how the "Pull to Refresh" looks like:

enter image description here

Padin215
  • 7,444
  • 13
  • 65
  • 103
  • 1
    just tryed your code on test project, and 'completion block' is ouputed to console. You tryed this on simulator or on device. Which iOS version you used, XCode version? – jamapag Feb 15 '13 at 19:10
  • Simulator, iOS 6.1, xcode 4.6. You did this in the `viewDidAppear:` method? – Padin215 Feb 15 '13 at 19:27
  • 1
    Hmm, I have same setup. Is `viewDidAppear` get called? – jamapag Feb 15 '13 at 19:29
  • Works for me. Xcode 4.6. I tested in the 5.0 simulator and the 6.1 simulator and both worked correctly. – rob mayoff Feb 15 '13 at 19:30
  • I can reproduce this problem. What are you trying to achieve? Maybe we can find an alternative solution. – pgb Feb 15 '13 at 21:10
  • To be able to animate the tableView.contentOffset back to 0. the over all effect is table view opens, it slides down to show the "Pull to Refresh" and slide back up after 3 seconds; kind of a peek at it so users know that option is available. – Padin215 Feb 15 '13 at 21:26
  • See my answer below. You just need to add a delayed call and you are all set! – pgb Feb 15 '13 at 21:29

2 Answers2

14

I used this and working fine. Its alternative solution.

[UIView animateWithDuration:0.5
                              delay:0.1
                            options: UIViewAnimationOptionCurveEaseOut
                         animations:^
         {
             CGRect frame = self.adBannerView.frame;

             self.adBannerView.frame = frame;
         }
                         completion:^(BOOL finished)
         {
         }];

try adding delay and options.

Rok Jarc
  • 18,765
  • 9
  • 69
  • 124
Guru
  • 21,652
  • 10
  • 63
  • 102
8

I was able to reproduce this issue and found a workaround.

When using a UIScrollView, which UITableView inherits from, you can't change its contentOffset is not an animatable property. Instead, you need to use the method setContentOffset:animated:.

So, what you need to do is as follows:

  1. Set your view controller as the UITableView delegate. I did in on viewDidAppear.
  2. Set a flag, so you know in the delegate that the scroll happened because you triggered.
  3. In the delegate method - (void)scrollViewDidEndScrollingAnimation:(UIScrollView *)scrollView, bounce back the animation (you could here add a delay by using performSelector:afterDelay:.

Here's the code:

@interface MyViewController ()

@property (assign, nonatomic) BOOL shouldReturn;

@end

@implementation MyViewController

-(void)viewDidAppear:(BOOL)animated {
    [super viewDidAppear:animated];
    if (TRUE) {
        NSLog(@"animating table view");
        self.shouldReturn = YES;
        self.tableView.delegate = self;
        [self.tableView setContentOffset:
                     CGPointMake(self.tableView.contentOffset.x,
                                 self.tableView.contentOffset.y - 60)
                                animated:YES];
    }
}

- (void)viewDidLoad
{
    [super viewDidLoad];
    if (TRUE) {
        UIRefreshControl *refresh = [[UIRefreshControl alloc] init];
        refresh.attributedTitle = [[NSAttributedString alloc] initWithString:@"Pull to Refresh"];
        [refresh addTarget:self action:@selector(refreshTableView:) forControlEvents:UIControlEventValueChanged];

        [self setRefreshControl:refresh];
    }
}

- (void)scrollViewDidEndScrollingAnimation:(UIScrollView *)scrollView {
    if (self.shouldReturn) {
        self.shouldReturn = NO;
        [self.tableView setContentOffset:CGPointZero animated:YES];
    }
}

@end
pgb
  • 24,813
  • 12
  • 83
  • 113
  • Ok, this works! i'm not sure why you set `self.tableView.delegate = self` though. I didn't add that and it works. I added in a `[self performSelector:@selector(test) withObject:nil afterDelay:2]' and works perfect, thanks! – Padin215 Feb 15 '13 at 21:35
  • I set the delegate because I don't have it wired on IB. I guess you didn't meet it because your view controller was already the table delegate. – pgb Feb 15 '13 at 22:48
  • I realize this is old as all, but @Log139's solution is fragile. You don't know exactly how long the animation will take. @pgb sets the delegate so he can get callbacks on `scrollViewDidEndScrollingAnimation` – Benhamine Jul 05 '17 at 17:29