UIScrollView ajusta contentOffset cuando cambia contentSize


Estoy ajustando el estado de un controlador de vista de detalle, justo antes de que se presione en un navigationController:

[self.detailViewController detailsForObject:someObject];
[self.navigationController pushViewController:self.detailViewController
                                     animated:YES];

En el DetailViewController reside una vista de desplazamiento. Qué contenido redimensiono basado en el objeto pasado:

- (void)detailsForObject:(id)someObject {
    // set some textView's content here
    self.contentView.frame = <rect with new calculated size>;

    self.scrollView.contentSize = self.contentView.frame.size;
    self.scrollView.contentOffset = CGPointZero;
}

Ahora, todo esto funciona, pero el ScrollView ajusta su contentOffset durante la animación de slide-in del NavigationController. El contentOffset se establecerá a la diferencia entre el último contentSize y el nuevo calculado. Esto significa que la segunda vez que abra DetailsView, el los detalles se desplazarán a alguna ubicación no deseada. Aunque estoy configurando contentOffset a CGPointZero explícitamente.

Encontré que restablecer el contentOffset en - viewWillAppear no tiene ningún efecto. Lo mejor que se me ocurrió es restablecer el contentOffset en viewDidAppear, causando un notable movimiento hacia arriba y hacia abajo del contenido:

- (void)viewDidAppear:(BOOL)animated {
    self.scrollView.contentOffset = CGPointZero;
}

¿Hay alguna manera de evitar que un UIScrollView ajuste su contentOffset cuando se cambia su contentSize?

Author: Jay Bhalani, 2011-06-29

7 answers

Ocurre cuando se empuja un UIViewController que contiene un UIScrollView usando un UINavigationController.

IOS 7

Solución 1 (Código)

Conjunto @property(nonatomic, assign) BOOL automaticallyAdjustsScrollViewInsets a NO.

Solución 2 (Storyboard)

Desmarca el Adjust Scroll View Insets

Ajustar las Inserciones de La Vista de Desplazamiento

IOS 6

Solución (Código)

Establece la propiedad UIScrollView contentOffset y contentInset en viewWillLayoutSubviews. Código de ejemplo:

- (void)viewWillLayoutSubviews{
  [super viewWillLayoutSubviews];
  self.scrollView.contentOffset = CGPointZero;
  self.scrollView.contentInset = UIEdgeInsetsZero;
}
 59
Author: KarenAnne,
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-12-02 10:14:32

La causa de este problema sigue sin estar clara, aunque he encontrado una solución. Al restablecer el tamaño y el desplazamiento del contenido antes de ajustarlos, UIScrollView no se animará:

- (void)detailsForObject:(id)someObject {
    // These 2 lines solve the issue:
    self.scrollView.contentSize = CGSizeZero;
    self.scrollView.contentOffset = CGPointZero;

    // set some textView's content here
    self.contentView.frame = <rect with new calculated size>;

    self.scrollView.contentSize = self.contentView.frame.size;
    self.scrollView.contentOffset = CGPointZero;
}
 14
Author: Berik,
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
2011-07-11 13:45:41

Tuve el mismo problema con un UIScrollView, donde el problema fue causado por no establecer el contentSize. Después de establecer el contentSize al número de elementos, este problema se resolvió.

self.headerScrollView.mainScrollview.contentSize = CGSizeMake(320 * self.sortedMaterial.count, 0);
 2
Author: Antoine,
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-09-23 13:29:19

Esto es lo que funcionó para mí:
En el storyboard, en el Inspector de tamaño para ScrollView, establezca el comportamiento de ajuste de Inserciones de contenido en"Nunca".

introduzca la descripción de la imagen aquí

 1
Author: Eden,
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
2018-07-13 20:54:52

¿Es su ScrollView la vista raíz del DetailViewController? Si es así, intente envolver la vista de desplazamiento en un UIView simple y haga de esta última la vista raíz de DetailViewController. Dado que UIView s no tienen una propiedad contentOffset, son inmunes a los ajustes de desplazamiento de contenido realizados por el controlador de navegación (debido a la barra de navegación, etc.).).

 0
Author: octy,
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
2011-06-29 16:21:38

Experimenté el problema, y para un caso específico - no ajusto el tamaño - utilicé lo siguiente:

float position = 100.0;//for example

SmallScroll.center = CGPointMake(position + SmallScroll.frame.size.width / 2.0, SmallScroll.center.y);

Lo mismo funcionaría con y: anotherPosition + SmallScroll.frame.size.height / 2.0

Así que si no necesita cambiar el tamaño, esta es una solución rápida e indolora.

 0
Author: Balázs Csordás,
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-11-05 15:31:11

Estaba experimentando un problema similar, donde UIKit estaba configurando el contentOffset de mi ScrollView durante las animaciones push.

Ninguna de estas soluciones funcionaba para mí, tal vez porque estaba apoyando iOS 10 y iOS 11.

Pude solucionar mi problema mediante la subclase de mi scrollview para evitar que UIKit cambiara mis compensaciones después de que el scrollview se hubiera eliminado de la ventana:

/// A Scrollview that only allows the contentOffset to change while it is in the window hierarchy. This can keep UIKit from resetting the `contentOffset` during transitions, etc.
class LockingScrollView: UIScrollView {
    override var contentOffset: CGPoint {
        get {
            return super.contentOffset
        }
        set {
            if window != nil {
                super.contentOffset = newValue
            }
        }
    }
}
 0
Author: Slimebaron,
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
2018-07-26 17:51:06