【发布时间】:2009-08-27 07:56:38
【问题描述】:
我想做一系列事情来响应某些 UITableView 动画的结束。例如,我希望表格视图单元格在通过 scrollToRowAtIndexPath 滚动到之后突出显示(通过 selectRowAtIndexPath)。
如何做到这一点?
【问题讨论】:
我想做一系列事情来响应某些 UITableView 动画的结束。例如,我希望表格视图单元格在通过 scrollToRowAtIndexPath 滚动到之后突出显示(通过 selectRowAtIndexPath)。
如何做到这一点?
【问题讨论】:
基本模板:
[UIView animateWithDuration:0.2 animations:^{
//do some animations, call them with animated:NO
} completion:^(BOOL finished){
//Do something after animations finished
}];
示例:滚动到第 100 行。完成后,获取该行的单元格,并将 tag=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];
}];
【讨论】:
我意识到这是一篇旧帖子,但我遇到了类似的问题,并创建了一个对我来说效果很好的解决方案。我应用了NSCookBook 上使用的技术来创建带有块的 UIAlertViews。我这样做的原因是因为我想使用内置动画而不是 UIView 的 + animateWithDuration:animations:completion:。随着 iOS 7 的变化,这些动画之间的差异更大。
您为 UITableView 创建一个类别,并在实现文件中创建一个内部私有类,该类将通过将块分配为您的 tableview 的委托来回调该块。问题是,在调用块之前,可以说原来的委托将“丢失”,因为新的委托是调用该块的对象。这就是为什么我在调用块以重新分配原始 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");
}
];
【讨论】:
如果您想在触发 scrollToRowAtIndexPath 后执行操作。
- (void)scrollToRowAtIndexPath:(NSIndexPath *)indexPath atScrollPosition:(UITableViewScrollPosition)scrollPosition animated:(BOOL)animated
你需要像这样创建一个 CAAnimation 指针
CAAnimation *myAnimation;
然后将delgate设置为self
myAnimation.delegate = self;
一旦你这样做了,下面这些委托方法应该会激活你可以放置你的代码的地方:
- (void)animationDidStart:(CAAnimation *)theAnimation
- (void)animationDidStop:(CAAnimation *)theAnimation finished:(BOOL)flag
【讨论】: