Obtenga UIScrollView para desplazarse hasta la parte superior

Respuestas:

316

ACTUALIZACIÓN PARA iOS 7

[self.scrollView setContentOffset:
    CGPointMake(0, -self.scrollView.contentInset.top) animated:YES];

ORIGINAL

[self.scrollView setContentOffset:CGPointZero animated:YES];

o si desea preservar la posición de desplazamiento horizontal y simplemente restablecer la posición vertical:

[self.scrollView setContentOffset:CGPointMake(self.scrollView.contentOffset.x, 0)
    animated:YES];
Rob Mayoff
fuente
50
Si está haciendo esto para iOS 7, es posible que tenga que tener en cuenta el UIScrollView contentInset, lamentablemente. [self.scrollView setContentOffset:CGPointMake(self.scrollView.contentOffset.x, -self.scrollView.contentInset.top) animated:YES];hace el trabajo por mí
runmad
11
Pude desplazarme hacia la parte superior, justo debajo de la barra de navegación y estado. [scrollView setContentOffset:CGPointMake(0, -scrollView.contentInset.top) animated:YES];Funciona en iOS 6 y 7
Amozoss
Esto no funcionó para mí, probablemente porque estoy haciendo algo loco con una vista invertida en el kit de sprite. Pero si alguien más está tan loco como yo, y su vista de desplazamiento está en la parte inferior de forma predeterminada, esto lo desplazará a la parte superior:[scrollView setContentOffset:CGPointMake(0, scrollView.contentSize.height-scrollView.frame.size.height) animated:YES];
GilesDMiddleton
Comentario al final del día: debe ajustar el contenido del contenido independientemente de la versión del sistema operativo. iOS 7 lo usa para permitir el contenido de desplazamiento debajo de la barra de estado, pero siempre ha sido expuesto como una propiedad, por lo que siempre ha sido utilizado por alguien.
Tommy
2
Para iOS 11+, la respuesta de Jakub Truhlář a continuación con el ajuste de contenido ajustado fue útil, al menos en mi caso.
tnev
61

Aquí hay una extensión Swift que lo hace fácil:

extension UIScrollView {
    func scrollToTop() {
        let desiredOffset = CGPoint(x: 0, y: -contentInset.top)
        setContentOffset(desiredOffset, animated: true)
   }
}

Uso:

myScrollView.scrollToTop()
Andrew Schreiber
fuente
40

iOS 11 y superior

intenta trabajar con el nuevo adjustedContentInset .

Por ejemplo (desplazarse hacia arriba):

var offset = CGPoint(
    x: -scrollView.contentInset.left, 
    y: -scrollView.contentInset.top)

if #available(iOS 11.0, *) {
    offset = CGPoint(
        x: -scrollView.adjustedContentInset.left, 
        y: -scrollView.adjustedContentInset.top)    
}

scrollView.setContentOffset(offset, animated: true)

Incluso si usas prefersLargeTitles, safe areaetc.

Jakub Truhlář
fuente
40

Para Swift 4

scrollView.setContentOffset(.zero, animated: true)
Rajasekhar Pasupuleti
fuente
23

Utilizar setContentOffset:animated:

[scrollView setContentOffset:CGPointZero animated:YES];
Bryan Chen
fuente
17

Respuesta para Swift 2.0 / 3.0 / 4.0 y iOS 7+:

let desiredOffset = CGPoint(x: 0, y: -self.scrollView.contentInset.top)
self.scrollView.setContentOffset(desiredOffset, animated: true)
vale la pena
fuente
8

En iOS7 tuve problemas para obtener una vista de desplazamiento particular para ir a la parte superior, que funcionó en iOS6, y usé esto para configurar la vista de desplazamiento para ir a la parte superior.

[self.myScroller scrollRectToVisible:CGRectMake(0, 0, 1, 1) animated:NO];
hoak
fuente
Tengo el mismo problema en iOS7. ¿Alguien sabe cómo habilitar esto para un UITableView?
DZenBot
1
Es curioso cómo funciona esto cuando animado es NO, pero no cuando animado es SÍ. En caso afirmativo, se desplaza casi hasta el topdevgm16
Matt Becker
4

Versión Swift 3.0.1 de la respuesta de rob mayoff :

self.scrollView.setContentOffset(
CGPoint(x: 0,y: -self.scrollView.contentInset.top),
animated: true)
Roni Leshes
fuente
2

Para replicar completamente el comportamiento scrollToTop de la barra de estado, no solo tenemos que configurar contentOffset, sino que también queremos asegurarnos de que se muestren los scrollIndicators. De lo contrario, el usuario puede perderse rápidamente.

El único método público para lograr esto es flashScrollIndicators. Desafortunadamente, llamarlo una vez después de configurar contentOffset no tiene ningún efecto porque se restablece de inmediato. Descubrí que funciona cuando hago el flash cada vez scrollViewDidScroll:.

// define arbitrary tag number in a global constants or in the .pch file
#define SCROLLVIEW_IS_SCROLLING_TO_TOP_TAG 19291

- (void)scrollContentToTop {
    [self.scrollView setContentOffset:CGPointMake(self.scrollView.contentOffset.x, -self.scrollView.contentInset.top) animated:YES];

    self.scrollView.tag = SCROLLVIEW_IS_SCROLLING_TO_TOP_TAG;
    dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.3 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
        self.scrollView.tag = 0;
    });
}

En su UIScrollViewDelegate (o UITable / UICollectionViewDelegate) implemente esto:

- (void)scrollViewDidScroll:(UIScrollView *)scrollView {
    if (scrollView.tag == SCROLLVIEW_IS_SCROLLING_TO_TOP_TAG) {
        [scrollView flashScrollIndicators];
    }
}

El retraso de ocultar es un poco más corto en comparación con el comportamiento scrollToTop de la barra de estado, pero aún se ve bien.

Tenga en cuenta que estoy abusando de la etiqueta de vista para comunicar el estado "isScrollingToTop" porque necesito esto en los controladores de vista. Si está usando etiquetas para otra cosa, es posible que desee reemplazar esto con un iVar o una propiedad.

Ortwin Gentz
fuente
No lo he probado, pero debería arrojar esto en el próximo runloop si solo usas DISPATCH_TIME_NOW en su lugar. Gracias por hacer este trabajo, no estoy seguro de que lo necesite todavía, pero es bueno saberlo.
Dan Rosenstark
Hace un tiempo y no recuerdo exactamente, pero creo que esto no funcionó. Aplazar al siguiente runloop suele ser lo primero que intento en tales casos.
Ortwin Gentz
2

Creo que tengo una respuesta que debería ser totalmente compatible con iOS 11, así como con versiones anteriores (para desplazamiento vertical)

Esto tiene en cuenta el nuevo ajustadoContentInset y también tiene en cuenta el desplazamiento adicional requerido cuando prefiereLargeTitles está habilitado en la de navegación, que parece requerir un desplazamiento adicional de 52 píxeles además del valor predeterminado.

Esto fue un poco complicado porque el ajustadoContentInset cambia según el estado de titleBar (título grande vs título pequeño), por lo que necesitaba verificar y ver cuál era la altura de titleBar y no aplicar el desplazamiento de 52px si ya está en el estado grande. No se pudo encontrar ningún otro método para verificar el estado de la barra de navegación, por lo que si alguien tiene una mejor opción que ver si la altura es> 44.0, me gustaría escucharla.

func scrollToTop(_ scrollView: UIScrollView, animated: Bool = true) {
    if #available(iOS 11.0, *) {
        let expandedBar = (navigationController?.navigationBar.frame.height ?? 64.0 > 44.0)
        let largeTitles = (navigationController?.navigationBar.prefersLargeTitles) ?? false
        let offset: CGFloat = (largeTitles && !expandedBar) ? 52: 0
        scrollView.setContentOffset(CGPoint(x: 0, y: -(scrollView.adjustedContentInset.top + offset)), animated: animated)
    } else {
        scrollView.setContentOffset(CGPoint(x: 0, y: -scrollView.contentInset.top), animated: animated)
    }
}

Inspirado en la solución de Jakub

usuario2898617
fuente
2

Es muy común cuando su barra de navegación se superpone a la pequeña porción del contenido scrollView y parece que el contenido no comienza desde la parte superior. Para arreglarlo hice 2 cosas:

  • Inspector de tamaño - Vista de desplazamiento - Inserciones de contenido -> Cambiar de automático a nunca.
  • Inspector de tamaño - Restricciones - "Alinear arriba a" (Restricciones de alineación superior) - Segundo elemento -> Cambiar de Superview.Top a Safe Area.Top y el valor (campo constante) establecido en 0

Inserciones de contenido - Nunca Alinee ScrolView.Top con Safe Area.Top

Vitya Shurapov
fuente
1

Desplazarse hasta parte superior de UITableViewController, UICollectionViewControllero cualquiera UIViewControllerque tengaUIScrollView

extension UIViewController {

  func scrollToTop(animated: Bool) {
    if let tv = self as? UITableViewController {
        tv.tableView.setContentOffset(CGPoint.zero, animated: animated)
    } else if let cv = self as? UICollectionViewController{
        cv.collectionView?.setContentOffset(CGPoint.zero, animated: animated)
    } else {
        for v in view.subviews {
            if let sv = v as? UIScrollView {
                sv.setContentOffset(CGPoint.zero, animated: animated)
            }
        }
    }
  }
}
Shoaib
fuente
0

En SWIFT 5, simplemente configure la compensación de contenido en cero

scrollView.setContentOffset(CGPoint.zero, animated: true)
Abdul Karim Khan
fuente
-4

Lo intenté de todas las formas. Pero nada funcionó para mí. Finalmente me gustó esto.

yo añadí self.view .addSubview(self.scroll) línea de código en el viewDidLoad. Después de comenzar a configurar el marco para la vista de desplazamiento y agregar componentes a la vista de desplazamiento.

Funcionó para mi.

Asegúrese de agregar una self.view .addSubview(self.scroll)línea al principio. entonces puede agregar elementos de la interfaz de usuario.

Narasimha Nallamsetty
fuente
Por favor borre esto. Si bien seguramente tenía sentido en ese momento, sus problemas de jerarquía de subvista no son relevantes para esta pregunta.
Dan Rosenstark
1
@Cristik si su vista de desplazamiento no está en la jerarquía de vista, o su computadora está apagada, por supuesto, nada de esto funcionará. Pero el OP preguntó algo bastante limitado
Dan Rosenstark