ios 当 scrollToRowAtIndexPath 完成动画时如何得到通知
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/4356256/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
How to get notified when scrollToRowAtIndexPath finishes animating
提问by Andrew
This is a follow-up to How to get notified when a tableViewController finishes animating the push onto a nav stack.
这是如何在 tableViewController 完成动画推送到导航堆栈时获得通知的后续内容。
In a tableView
I want to deselect a row with animation, but only after the tableView has finishedanimating the scroll to the selected row. How can I be notified when that happens, or what method gets called the moment that finishes.
在 atableView
我想取消选择带有动画的行,但只有在 tableView完成动画滚动到所选行之后。发生这种情况时我如何得到通知,或者在完成时调用什么方法。
This is the order of things:
这是事情的顺序:
- Push view controller
- In
viewWillAppear
I select a certain row. - In
viewDidAppear
IscrollToRowAtIndexPath
(to the selected row). - Then when that finishes scrolling I want to
deselectRowAtIndexPath: animated:YES
- 推送视图控制器
- 在
viewWillAppear
我选择某一行。 - 在
viewDidAppear
IscrollToRowAtIndexPath
(到所选行)。 - 然后当完成滚动时我想
deselectRowAtIndexPath: animated:YES
This way, the user will know why they were scrolled there, but then I can fade away the selection.
Step 4 is the part I haven't figured out yet. If I call it in viewDidAppear
then by the time the tableView scrolls there, the row has been deselected already which is no good.
这样,用户就会知道他们为什么在那里滚动,但随后我可以淡出选择。
第 4 步是我还没有弄清楚的部分。如果我调用它,viewDidAppear
那么当 tableView 滚动到那里时,该行已经被取消选择,这是不好的。
回答by James Huddleston
You can use the table view delegate's scrollViewDidEndScrollingAnimation:
method. This is because a UITableView
is a subclass of UIScrollView
and UITableViewDelegate
conforms to UIScrollViewDelegate
. In other words, a table view is a scroll view, and a table view delegate is also a scroll view delegate.
您可以使用表视图委托的scrollViewDidEndScrollingAnimation:
方法。这是因为 aUITableView
是 的子类UIScrollView
并UITableViewDelegate
符合UIScrollViewDelegate
。换句话说,表视图是滚动视图,表视图委托也是滚动视图委托。
So, create a scrollViewDidEndScrollingAnimation:
method in your table view delegate and deselect the cell in that method. See the reference documentation for UIScrollViewDelegate
for information on the scrollViewDidEndScrollingAnimation:
method.
因此,scrollViewDidEndScrollingAnimation:
在您的表视图委托中创建一个方法并取消选择该方法中的单元格。有关UIScrollViewDelegate
该scrollViewDidEndScrollingAnimation:
方法的信息,请参阅参考文档。
回答by Pung Worathiti Manosroi
try this
尝试这个
[UIView animateWithDuration:0.3 animations:^{
[yourTableView scrollToRowAtIndexPath:indexPath
atScrollPosition:UITableViewScrollPositionTop
animated:NO];
} completion:^(BOOL finished){
//do something
}];
Don't forget to set animated to NO, the animation of scrollToRow will be overridden by UIView animateWithDuration.
不要忘记将animated 设置为NO,scrollToRow 的动画将被UIView animateWithDuration 覆盖。
Hope this help !
希望这有帮助!
回答by erik
To address Ben Packard's comment on the accepted answer, you can do this. Test if the tableView can scroll to the new position. If not, execute your method immediately. If it can scroll, wait until the scrolling is finished to execute your method.
要解决 Ben Packard 对已接受答案的评论,您可以这样做。测试 tableView 是否可以滚动到新位置。如果没有,立即执行你的方法。如果可以滚动,请等到滚动完成后再执行您的方法。
- (void)someMethod
{
CGFloat originalOffset = self.tableView.contentOffset.y;
[self.tableView scrollToRowAtIndexPath:path atScrollPosition:UITableViewScrollPositionMiddle animated:NO];
CGFloat offset = self.tableView.contentOffset.y;
if (originalOffset == offset)
{
// scroll animation not required because it's already scrolled exactly there
[self doThingAfterAnimation];
}
else
{
// We know it will scroll to a new position
// Return to originalOffset. animated:NO is important
[self.tableView setContentOffset:CGPointMake(0, originalOffset) animated:NO];
// Do the scroll with animation so `scrollViewDidEndScrollingAnimation:` will execute
[self.tableView scrollToRowAtIndexPath:path atScrollPosition:UITableViewScrollPositionMiddle animated:YES];
}
}
- (void)scrollViewDidEndScrollingAnimation:(UIScrollView *)scrollView
{
[self doThingAfterAnimation];
}
回答by Mr. T
You can include the scrollToRowAtIndexPath:
inside a [UIView animateWithDuration:...]
block which will trigger the completion block after all included animations conclude. So, something like this:
您可以scrollToRowAtIndexPath:
在[UIView animateWithDuration:...]
块内部包含在所有包含的动画结束后触发完成块。所以,像这样:
[UIView
animateWithDuration:0.3f
delay:0.0f
options:UIViewAnimationOptionAllowUserInteraction
animations:^
{
// Scroll to row with animation
[self.tableView scrollToRowAtIndexPath:indexPath
atScrollPosition:UITableViewScrollPositionTop
animated:YES];
}
completion:^(BOOL finished)
{
// Deselect row
[self.tableView deselectRowAtIndexPath:indexPath animated:YES];
}];
回答by Drew
Implementing this in a Swift extension.
在 Swift 扩展中实现这一点。
//strong ref required
private var lastDelegate : UITableViewScrollCompletionDelegate! = nil
private class UITableViewScrollCompletionDelegate : NSObject, UITableViewDelegate {
let completion: () -> ()
let oldDelegate : UITableViewDelegate?
let targetOffset: CGPoint
@objc private func scrollViewDidEndScrollingAnimation(scrollView: UIScrollView) {
scrollView.delegate = oldDelegate
completion()
lastDelegate = nil
}
init(completion: () -> (), oldDelegate: UITableViewDelegate?, targetOffset: CGPoint) {
self.completion = completion
self.oldDelegate = oldDelegate
self.targetOffset = targetOffset
super.init()
lastDelegate = self
}
}
extension UITableView {
func scrollToRowAtIndexPath(indexPath: NSIndexPath, atScrollPosition scrollPosition: UITableViewScrollPosition, animated: Bool, completion: () -> ()) {
assert(lastDelegate == nil, "You're already scrolling. Wait for the last completion before doing another one.")
let originalOffset = self.contentOffset
self.scrollToRowAtIndexPath(indexPath, atScrollPosition: scrollPosition, animated: false)
if originalOffset.y == self.contentOffset.y { //already at the right position
completion()
return
}
else {
let targetOffset = self.contentOffset
self.setContentOffset(originalOffset, animated: false)
self.delegate = UITableViewScrollCompletionDelegate(completion: completion, oldDelegate: self.delegate, targetOffset:targetOffset)
self.scrollToRowAtIndexPath(indexPath, atScrollPosition: scrollPosition, animated: true)
}
}
}
This works for most cases although the TableView delegate is changed during the scroll, which may be undesired in some cases.
这适用于大多数情况,尽管在滚动期间更改了 TableView 委托,这在某些情况下可能是不希望的。