cocoa-touch - cocoa touch tutorial
Cómo recibir una notificación cuando scrollToRowAtIndexPath termina de animar (5)
Implementando esto en una extensión 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)
}
}
}
Esto funciona en la mayoría de los casos aunque el delegado TableView se modifique durante el desplazamiento, lo que puede no desearse en algunos casos.
Esta es una continuación de Cómo recibir una notificación cuando un TableViewController termina de animar la inserción en una pila de navegación.
En tableView
, quiero deseleccionar una fila con animación, pero solo después de que tableView haya terminado de animar el desplazamiento a la fila seleccionada. ¿Cómo puedo recibir una notificación cuando eso sucede, o qué método se llama en el momento en que termina?
Este es el orden de las cosas:
- Controlador de vista push
- En
viewWillAppear
selecciono una cierta fila. - En
viewDidAppear
IscrollToRowAtIndexPath
(a la fila seleccionada). - Luego, cuando eso termine de desplazarse, quiero
deselectRowAtIndexPath: animated:YES
De esta forma, el usuario sabrá por qué se desplazaron allí, pero luego puedo desvanecerme la selección.
El paso 4 es la parte que todavía no he descifrado. Si lo llamo en viewDidAppear
cuando viewDidAppear
se desplace allí, la fila ya no está seleccionada, lo cual no es bueno.
Para abordar el comentario de Ben Packard sobre la respuesta aceptada, puede hacer esto. Pruebe si tableView puede desplazarse a la nueva posición. Si no, ejecuta tu método de inmediato. Si puede desplazarse, espere hasta que el desplazamiento finalice para ejecutar su método.
- (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];
}
Puede incluir scrollToRowAtIndexPath:
dentro de un [UIView animateWithDuration:...]
que activará el bloque de finalización después de que concluyan todas las animaciones incluidas. Entonces, algo como esto:
[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];
}];
Puede usar el método scrollViewDidEndScrollingAnimation:
del delegado de la vista de tabla. Esto se debe a que UITableView
es una subclase de UIScrollView
y UITableViewDelegate
cumple con UIScrollViewDelegate
. En otras palabras, una vista de tabla es una vista de desplazamiento, y un delegado de vista de tabla es también un delegado de vista de desplazamiento.
Por lo tanto, cree un método scrollViewDidEndScrollingAnimation:
en su delegado de vista de tabla y anule la selección de la celda en ese método. Consulte la documentación de referencia para UIScrollViewDelegate
para obtener información sobre el método scrollViewDidEndScrollingAnimation:
.
prueba esto
[UIView animateWithDuration:0.3 animations:^{
[yourTableView scrollToRowAtIndexPath:indexPath
atScrollPosition:UITableViewScrollPositionTop
animated:NO];
} completion:^(BOOL finished){
//do something
}];
No se olvide de configurar animada a NO, la animación de scrollToRow será anulada por UIView animateWithDuration.
Espero que esto ayude !