Obteniendo la página actual

97

En mi vista de desplazamiento, quiero obtener la página actual que se muestra (tal vez la página no es el término correcto). No puedo encontrar ninguna variable que contenga esto. Pero creo que debe mantenerse en algún lugar, ya que el indicador puede mostrar qué vista secundaria de la vista de desplazamiento se está mostrando actualmente.

¿Está completamente oculto para nosotros o hay alguna forma de acceder a él?

TheNeil
fuente

Respuestas:

263

No hay ninguna UIScrollViewpropiedad para la página actual. Puedes calcularlo con:

int page = scrollView.contentOffset.x / scrollView.frame.size.width;

Si desea redondear hacia arriba o hacia abajo a la página más cercana, use:

CGFloat width = scrollView.frame.size.width;
NSInteger page = (scrollView.contentOffset.x + (0.5f * width)) / width;
AlexVogel
fuente
7
¡No olvide usar UIScrollViewDelegatepara obtener la página actual cuando el usuario se desplaza!
Sam Spencer
Esto puede tener problemas cuando se trata de rotación.
Jason McCreary
por favor agregue la versión rápida
fnc12
1
Esto no siempre funciona, a veces el ancho del marco es incorrecto.
Rodrigo Ruiz
Esto no siempre funciona. A veces obtengo la página como 0, lo cual es incorrecto en mi caso.
Sneha
32

Te recomiendo que uses este código

int indexOfPage = scrollView.contentOffset.x / scrollView.frame.size.width;

pero si usa este código, su vista no necesita estar exactamente en la página que le da indexOfPage. Es porque también te recomiendo que uses este código solo en este método

-(void)scrollViewDidEndDecelerating:(UIScrollView *)scrollView{}

que se llama cuando su scrollView termina de desplazarse y para que el número de su página sea realmente nítido

Le recomiendo que configure su scrollView en paginado habilitado con este código

[scrollView setPagingEnabled:YES];

Así que finalmente debería verse así

-(void) methodWhereYouSetYourScrollView
{
   //set scrollView
   [scrollView setPagingEnabled:YES];
   scrollView.delegate = self;
}

-(void)scrollViewDidEndDecelerating:(UIScrollView *)scrollView
{
   int indexOfPage = scrollView.contentOffset.x / scrollView.frame.size.width;
   //your stuff with index
}
Jiří Zahálka
fuente
no funciona en el dispositivo iOS7 (compilado con XCODE 6.2) contentOffset.x es igual a 639 en lugar de 640 (no me preguntes por qué ...) cuando scrollViewDidEndDecelerating. user363349 la respuesta es correcta: return floor ((self.contentOffset.x - pageWidth / 2) / pageWidth) + 1;
Vassily
Esto no siempre funciona. A veces obtengo la página como 0, lo cual es incorrecto en mi caso.
Sneha
30

En rápido lo haría en extensión:

extension UIScrollView {
    var currentPage:Int{
        return Int((self.contentOffset.x+(0.5*self.frame.size.width))/self.frame.width)+1
    }
}

Entonces solo llama:

scrollView.currentPage
Andrius Steponavičius
fuente
10
Casi perfecto, tuve que eliminar el +1 al final ya que todo es cero en mi mundo
mvandillen
12

Como arriba pero como categoría


@interface UIScrollView (CurrentPage)
-(int) currentPage;
@end
@implementation UIScrollView (CurrentPage)
-(int) currentPage{
    CGFloat pageWidth = self.frame.size.width;
    return floor((self.contentOffset.x - pageWidth / 2) / pageWidth) + 1;
}
@end
user363349
fuente
6
Eso es exagerado, solo use return round (self.contentOffset.x / self.frame.size.width); Mucho más simple y fácil de entender ..
Leonard Pauli
-1 @LeonardPauli. La implementación anterior devuelve la página que es visible en más del 50%. La implementación ingenua solo cambia el valor de la página cuando la subvista de scrollview ocupa todos los límites de scrollview.
usuario
1
@user Primero, floor () redondea siempre hacia abajo, y round () redondea hacia arriba si la parte decimal es> = 5, de lo contrario hacia abajo. Dicho esto, piso (a) = redondo (a-0.5). Hagamos algo de álgebra simple. piso ((ab / 2) / b) +1 = piso (a / b-0.5) +1 = ronda (a / b-0.5-0.5) +1 = ronda (a / b-1) +1 = ronda ( a / b). ¡Mira! ¡Parece piso ((ab / 2) / b) +1 = round (a / b)! Mathemagical.
Leonard Pauli
Pero sí, si por alguna razón hubiera usado piso en su lugar, ¡entonces habrías tenido toda la razón! ;)
Leonard Pauli
8

Otra forma :

extension MyViewController: UIScrollViewDelegate {
    func scrollViewDidEndDecelerating(_ scrollView: UIScrollView) {
        let width = scrollView.frame.width
        let page = Int(round(scrollView.contentOffset.x/width))
        print("CurrentPage:\(page)")
    }
}
Hemang
fuente
6

Simplemente divida el desplazamiento actual por el tamaño de la página:

CGFloat pageNum = (int)(scrollView.contentOffset.x / scrollView.frame.size.width);
aoakenfo
fuente
11
¿Transmitir a int y luego asignar a un flotador? ¿Por qué no hacer que pageNum también sea int;)
Klaas
6

Aquí ya hay algunas buenas respuestas. Sin embargo, para escenarios donde el contenido no encaja exactamente en una página, y si, como yo, desea usar el resultado para un UIPageControl, entonces es esencial usar elceil función.

Tomemos un ejemplo en el que tengo "cuatro y un poco" páginas de contenido.

Basaré esto en mi ejemplo actual de la vida real. El ancho del tamaño del contenido es 3140 puntos. Según el tamaño del marco de vista de mi colección, el ancho de la página es 728.

Entonces el número de páginas es igual a:

 3140 / 728 = 4.313 

Mi numberOfPagesva a ser cinco. Cuatro de los cuales se mostrarán en su totalidad, y el último de los cuales, la página cinco, mostrará el 0.313contenido restante .

Ahora, numberOfPagesser cinco significa que los índices de página serán 0, 1, 2, 3 y 4.

Cuando deslizo el dedo hacia la derecha, paginando hacia el desplazamiento final, el scrollViewDidEndDecelerating método da un desplazamiento X final de 2412.

Aplicando el cálculo de redondeo:

2412 / 728 = 3.313 then rounded = 3

Eso es incorrecto. La página que el usuario está viendo por desplazamiento debe ser:

Offset / Page User Is Viewing
0        0
728      1
1456     2
2184     3
2412     4

El cálculo correcto usando ceil:

private func pageForOffset(offset:CGFloat, pageWidth width:CGFloat) -> Int
{
    let page = Int(ceil(offset / width))
    NSLog("\(__FUNCTION__) offset \(offset) width \(width) page \(page) ")
    return page
}
Max MacLeod
fuente
4

Por rapidez, solo usaría esto

    let width = scrollView.frame.width
    let page = round(scrollView.contentOffset.x/width)

Bastante sencillo, básicamente toma la posición x de la vista de desplazamiento, la divide por el ancho de la vista de desplazamiento y luego la redondea.

neptuno
fuente
3

En xCode 7.x swift 2.x puede hacer:

//MARK: - ScrollView Extensions
// Get the current page number
extension UIScrollView {
    var currentPage: Int {
        return Int(round(self.contentOffset.x / self.bounds.size.width))
    }

// If you have reversed offset (start from contentSize.width to 0)
    var reverseCurrentPage: Int {
        return Int(round((contentSize.width - self.contentOffset.x) / self.bounds.size.width))-1
    }
}
Alessandro Ornano
fuente
3

La solución de Aoakenfo es asombrosa, esta es otra solución que combina su código con la función scrollViewDidScroll y PageController

- (void)scrollViewDidScroll:(UIScrollView *)sender {
    if (sender == self.scroll) {
        int pageNum = (int)(self.scrPage.contentOffset.x / self.scrPage.frame.size.width);
        self.pagecontroller.currentPage =pageNum;
    }
}
pabloverd
fuente
1
Esto es codicioso, no vago ... Tampoco es MVC. Una forma mucho más sencilla es invalidar la página actual en el desplazamiento y configurarla solo cuando se solicite ... todo desde una subclase o categoría en UIScrollView
2

Extraje esto de un par de nuestras aplicaciones ...

- (NSInteger)currentPage
{
    if (0 == self.frame.size.width) {
        NSLog(@"frame width == 0!");
        return 0;
    }
    if (! self.currentPageValid) {
        _currentPage = round(self.contentOffset.x / self.frame.size.width);
        self.currentPageValid = YES;
    }
    return _currentPage;
}

Fuente completa aquí


fuente
1

¿Está utilizando un UIPageControl? Si es así, tiene una currentPagepropiedad. De lo contrario, creo que deberá calcular el índice de la página a partir del desplazamiento scrollView.

Rengers
fuente
0

Si alguien busca la forma de hacerlo en C # para Xamarin

    public int CurrentIndex
    {
        get => (int)Math.Round(this.scrollView.ContentOffset.X / this.scrollView.Frame.Width);
        set => this.scrollView.ScrollRectToVisible(new CGRect(new CGPoint(this.scrollView.Frame.Size.Width * value, 0), this.scrollView.Frame.Size), true);
    }

Este getter y Setter deben proporcionarle la página actual y permitirle desplazarse a la página especificada

soan saini
fuente
0

Extensión Swift 5.1+ UIScrollView (se omite la palabra clave de retorno)

extension UIScrollView {

    var currentPage: Int {
        Int(round(self.contentOffset.x / self.frame.width))
    }
}
Diego Carrera
fuente