Cocoa touch 如何在ScrollToRowatineXpath完成动画制作时获得通知
这是一项后续行动 在Cocoa touch 如何在ScrollToRowatineXpath完成动画制作时获得通知,cocoa-touch,ios,Cocoa Touch,Ios,这是一项后续行动 在tableView中,我想取消选择带有动画的行,但只有在tableView完成滚动到所选行的动画制作之后。发生这种情况时如何通知我,或者在完成时调用什么方法 事情是这样的: 推式视图控制器 在视图中将出现中,我选择某一行 在视图中显示IscrollToRowatinedexpath(到所选行) 然后,当滚动结束时,我想取消浏览索引路径:动画:是 这样,用户就可以知道为什么会在那里滚动,但我可以淡出选择。 第四步是我还没有弄明白的部分。如果我在视图中调用它,那么当tableVi
tableView
中,我想取消选择带有动画的行,但只有在tableView完成滚动到所选行的动画制作之后。发生这种情况时如何通知我,或者在完成时调用什么方法
事情是这样的:
视图中将出现
中,我选择某一行视图中显示IscrollToRowatinedexpath
(到所选行)
取消浏览索引路径:动画:是
第四步是我还没有弄明白的部分。如果我在
视图中调用它,那么当tableView在那里滚动时,该行已经被取消选择,这是不好的。您可以使用table view委托的滚动视图显示滚动提示:
方法。这是因为UITableView
是UIScrollView
的子类,UITableViewDelegate
符合UIScrollViewDelegate
。换句话说,表视图是滚动视图,表视图委托也是滚动视图委托
因此,在表视图委托中创建一个ScrollViewDiEndScrollingAnimation:
方法,并取消选择该方法中的单元格。有关ScrollViewDiEndScrollingAnimation:
方法的信息,请参阅UIScrollViewDelegate
的参考文档。要解决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];
}
您可以在[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];
}];
试试这个
[UIView animateWithDuration:0.3 animations:^{
[yourTableView scrollToRowAtIndexPath:indexPath
atScrollPosition:UITableViewScrollPositionTop
animated:NO];
} completion:^(BOOL finished){
//do something
}];
不要忘记将动画设置为否,scrollToRow的动画将被UIView animateWithDuration覆盖
希望这有帮助 在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)
}
}
}
这适用于大多数情况,尽管在滚动过程中更改了TableView委托,但在某些情况下可能是不需要的。Swift 5
ScrollViewDiEndScrollingAnimation(\uScrollView:UIScrollView)
delegate方法确实是对滚动到行动画执行完成的最佳方法,但有两件事值得注意:
首先,文档错误地指出,此方法仅在响应setContentOffset
和scrollRectToVisible
时调用;它也被调用以响应scrollToRow
()
第二,尽管在主线程上调用了该方法,但如果在此处运行后续动画(在滚动完成之后),它仍然会挂接(这可能是UIKit中的错误,也可能不是)。因此,只需将任何后续动画分派回主队列,即可确保动画将在当前主任务(似乎包括滚动到行动画)结束后开始。这样做会给你一个真正完成的外观
func scrollViewDidEndScrollingAnimation(_ scrollView: UIScrollView) {
DispatchQueue.main.async {
// execute subsequent animation here
}
}
如果iOS提供一个带有完成块的版本(如UIView animateWithDuration:animations:completion
),那么该通知可以是特定于上下文的……如果表视图决定不需要滚动动画(因为行已经在屏幕上),该怎么办?如果滚动动画方法不启动,则永远不会取消选择该行。@BenPackard,您可以事先检查一下[myTableView.indexPathsForVisibleRows containsObject:myIndexPath]
该方法在iOS 7上未调用。1使用[self.tableView.indexPathsForVisibleRows containsObject:path]
如何?如果indexPath不可见,则肯定需要滚动以正确定位,因此,在这种情况下,您可以跳过contentOffset
fiddling。但是,如果indexPath可见,tableView可能无法将其滚动到位,因此您应该检查ContentOffset(如上所示)。聪明:)尽管这会覆盖ScrollToRowatineXpath的默认动画持续时间?正确,它会覆盖默认持续时间,但取决于您设置的值,它可以让你的应用程序表现得清晰/独特(这可能是一件好事)或者,您可以找到一个非常接近默认值的值,用户几乎无法识别。我发现此解决方案在滚动长列表时不幸会导致一些瑕疵:滚动停止时,除单元格外的所有单元格都不显示,并显示为白色,导致闪烁。对自身的弱引用(me
)这也是不合理的。从iOS 9开始,如果使用0.00的动画duration
和NO
的animated
,滚动长列表似乎不会“闪烁”。基于这个建议,我可以做我想做的事情,所以我想我拥有你一个:)小心使用这个解决方案:我使用这个方法有一段时间了,直到我在滚动到的单元格中看到奇怪的行为。隐藏的图像将显示。。。无法解释。视图调试将显示它们不可见。但当它们在设备上运行时。我将问题隔离到ScrollToRowatineXpath,并将动画设置为动画块内部的NO。将其移到动画块外,不会出现问题。但是没有动画。。。因此,这种技术可能会导致问题。我更新了使用James Huddleston的ScrollViewDiEndScrollingAnimation解决方案来解决这个问题。在iOS13中,我看到这样做后cpu使用率超过了100%。还有动画