Как узнать, когда завершена анимация UITableView? - PullRequest
11 голосов
/ 27 августа 2009

Я хочу сделать ряд вещей в ответ на завершение некоторых анимаций UITableView. Например, я хочу, чтобы ячейка табличного представления выделялась (через selectRowAtIndexPath) после того, как она была прокручена через scrollToRowAtIndexPath.

Как это можно сделать?

Ответы [ 3 ]

29 голосов
/ 09 октября 2011

Базовый шаблон:

[UIView animateWithDuration:0.2 animations:^{
    //do some animations, call them with animated:NO
} completion:^(BOOL finished){
    //Do something after animations finished     
}];   

Пример: выделите строку 100. Когда закончите, получите ячейку в этой строке и создайте представление содержимого ячейки с тегом = 1 для firstResponder:

[UIView animateWithDuration:0.2 animations:^{
        [self.tableView scrollToRowAtIndexPath:[NSIndexPath indexPathForRow:100 inSection:0] atScrollPosition:UITableViewScrollPositionTop animated:NO];
    } completion:^(BOOL finished){
        //Do something after scrollToRowAtIndexPath finished, e.g.:
        UITableViewCell *nextCell = [self.tableView cellForRowAtIndexPath:[NSIndexPath indexPathForRow:100 inSection:0]];
        [[nextCell.contentView viewWithTag:1] becomeFirstResponder];        
    }];   
2 голосов
/ 25 октября 2013

Я понимаю, что это старый пост, но у меня была похожая проблема, и я нашел решение, которое хорошо сработало для меня. Я применил методы, используемые в NSCookBook для создания UIAlertViews с блоками. Причина, по которой я пошел на это, заключалась в том, что я хотел использовать встроенные анимации, а не UIView + animateWithDuration: animations: завершение :. Существует большая разница между этими анимациями при переходе на iOS 7.

Вы создаете категорию для UITableView, а в файле реализации вы создаете внутренний закрытый класс, который будет вызывать блок обратно, назначая его в качестве делегата вашего табличного представления. Подвох в том, что до тех пор, пока не будет вызван блок, исходный делегат будет, так сказать, «потерян», поскольку новый делегат является объектом, который будет вызывать блок. Вот почему я поместил уведомление, чтобы отправить сообщение, когда блок был вызван, чтобы переназначить оригинальный UITableViewDelegate. Этот код был проверен и работает на моем конце.

// Header file
@interface UITableView (ScrollDelegateBlock)

-(void)scrollToRowAtIndexPath:(NSIndexPath *)indexPath
             atScrollPosition:(UITableViewScrollPosition)scrollPosition
                     animated:(BOOL)animated
               scrollFinished:(void (^)())scrollFinished;

@end


// Implementation file
#import "UITableView+ScrollDelegateBlock.h"
#import <objc/runtime.h>

NSString *const BLOCK_CALLED_NOTIFICATION = @"BlockCalled";

@interface ScrollDelegateWrapper : NSObject <UITableViewDelegate>

@property (copy) void(^scrollFinishedBlock)();

@end

@implementation ScrollDelegateWrapper

-(void)scrollViewDidEndScrollingAnimation:(UIScrollView *)scrollView {
    if (self.scrollFinishedBlock) {
        [[NSNotificationCenter defaultCenter] postNotificationName:BLOCK_CALLED_NOTIFICATION object:nil];
        self.scrollFinishedBlock();
    }
}

@end

static const char kScrollDelegateWrapper;

static id<UITableViewDelegate>previousDelegate;

@implementation UITableView (ScrollDelegateBlock)

-(void)scrollToRowAtIndexPath:(NSIndexPath *)indexPath
             atScrollPosition:(UITableViewScrollPosition)scrollPosition
                     animated:(BOOL)animated
               scrollFinished:(void (^)())scrollFinished {
    previousDelegate = self.delegate;
    ScrollDelegateWrapper *scrollDelegateWrapper = [[ScrollDelegateWrapper alloc] init];
    scrollDelegateWrapper.scrollFinishedBlock = scrollFinished;
    self.delegate = scrollDelegateWrapper;

    objc_setAssociatedObject(self, &kScrollDelegateWrapper, scrollDelegateWrapper, OBJC_ASSOCIATION_RETAIN_NONATOMIC);

    [self scrollToRowAtIndexPath:indexPath atScrollPosition:scrollPosition animated:animated];

    [[NSNotificationCenter defaultCenter] addObserver:self
                                             selector:@selector(blockCalled:)
                                                 name:BLOCK_CALLED_NOTIFICATION
                                               object:nil];
}

/*
 * Assigns delegate back to the original delegate
 */
-(void) blockCalled:(NSNotification *)notification {
    self.delegate = previousDelegate;
    [[NSNotificationCenter defaultCenter] removeObserver:self
                                                    name:BLOCK_CALLED_NOTIFICATION
                                                  object:nil];
}

@end

Затем вы можете вызвать метод, как и любой другой, с блоком:

[self.tableView scrollToRowAtIndexPath:self.currentPath
                          atScrollPosition:UITableViewScrollPositionMiddle
                                  animated:YES
                            scrollFinished:^{
                                NSLog(@"scrollFinished");
                            }
];
0 голосов
/ 20 сентября 2009

Хорошо, если вы хотите выполнить действие после запуска scrollToRowAtIndexPath.

- (void)scrollToRowAtIndexPath:(NSIndexPath *)indexPath atScrollPosition:(UITableViewScrollPosition)scrollPosition animated:(BOOL)animated

Вам нужно создать указатель CAAnimation, как

CAAnimation *myAnimation;

Затем установите delgate на себя

myAnimation.delegate = self;

После того, как вы это сделаете, должны активироваться следующие методы делегата, куда вы можете поместить свой код:

- (void)animationDidStart:(CAAnimation *)theAnimation

- (void)animationDidStop:(CAAnimation *)theAnimation finished:(BOOL)flag
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...