Configurar contentOffset activa mediante programación scrollViewDidScroll


Tengo unos cuantos UIScrollView en una página. Puedes desplazarlos de forma independiente o bloquearlos juntos y desplazarlos como uno solo. El problema ocurre cuando están bloqueados.

Utilizo UIScrollViewDelegate y scrollViewDidScroll: para rastrear el movimiento. Busco el contentOffset del UIScrollView que cambió y luego refleja el cambio a otras vistas de desplazamiento configurando su propiedad contentOffset para que coincida.

Genial.... excepto que noté un montón de llamadas extra. Cambiar programáticamente el contentOffset de mis vistas de desplazamiento activa el método delegado scrollViewDidScroll: para ser llamado. He intentado usar setContentOffset:animated: en su lugar, pero todavía estoy recibiendo el disparador en el delegado.

¿Cómo puedo modificar mis contentOffsets programáticamente para no activar scrollViewDidScroll:?

Notas de aplicación.... Cada UIScrollView es parte de un UIView personalizado que usa el patrón delegado para llamar a la subclase UIViewController que se encarga de coordinar los diversos valores contentOffset.

Author: DBD, 2012-02-23

6 answers

Es posible cambiar el desplazamiento de contenido de un UIScrollView sin activar la devolución de llamada delegada scrollViewDidScroll:, estableciendo los límites de la UIScrollView con el origen establecido en el desplazamiento de contenido deseado.

CGRect scrollBounds = scrollView.bounds;
scrollBounds.origin = desiredContentOffset;
scrollView.bounds = scrollBounds;
 100
Author: Tark,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2012-02-23 18:05:05

Intenta

id scrollDelegate = scrollView.delegate;
scrollView.delegate = nil;
scrollView.contentOffset = point;
scrollView.delegate = scrollDelegate;

Funcionó para mí.

 66
Author: Abhijit,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2013-07-25 11:10:25

¿Qué hay de usar las propiedades existentes de UIScrollView?

if(scrollView.isTracking || scrollView.isDragging || scrollView.isDecelerating) {
    //your code
}
 34
Author: Kukosk,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2014-11-08 16:35:08

Simplificando la respuesta de @Tark, puedes colocar el scrollview sin disparar scrollViewDidScroll en una línea como esta:

scrollView.bounds.origin = CGPoint(x:0, y:100); // whatever values you'd like
 6
Author: SimplGy,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2015-03-10 12:33:09

Otro enfoque es agregar cierta lógica en su delegado de scrollViewDidScroll para determinar si el cambio en el desplazamiento de contenido se activó de forma programática o mediante el toque del usuario.

  • Agregue una variable booleana 'isManualScroll' a su clase.
  • Establezca su valor inicial en false.
  • En scrollViewWillBeginDragging establecerlo en true.
  • En su scrollViewDidScroll compruebe que es verdadero y solo responda si lo es.
  • En scrollViewDidEndDecelerating establécelo a false.
  • En scrollViewWillEndDragging agregue lógica para establecerla en false si la velocidad es 0 (ya que scrollViewDidEndDecelerating no se llamará en este caso).
 5
Author: Jake MacMullin,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2014-09-11 01:39:33

Esta no es una respuesta directa a la pregunta, pero si usted está recibiendo lo que parecen ser falsos tales mensajes, también puede ser porque usted está cambiando los límites. Estoy usando un código de ejemplo de Apple con un método "tilePages" que elimina y agrega subview a una vista de desplazamiento. Esto infrecuentemente resulta en scrollViewDidScroll: mensajes adicionales llamados inmediatamente, por lo que entra en una recursión que seguramente no esperaba. En mi caso tengo un accidente desagradable imposible de encontrar.

Lo que yo terminó haciendo estaba haciendo cola de la llamada en la cola principal:

- (void)scrollViewDidScroll:(UIScrollView *)scrollView
{
    if(scrollView == yourScrollView) {
        // dispatch fixes some recursive call to scrollViewDidScroll in tilePages (related to removeFromSuperView)
        // The reason can be found here: http://stackoverflow.com/questions/9418311
        dispatch_async(dispatch_get_main_queue(), ^{ [self tilePages]; });
    }
}
 4
Author: David H,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2012-03-31 21:00:26