Obtendo a página atual

97

Na minha visualização de rolagem, quero obter a página atual que está sendo exibida (talvez página não seja o termo correto). Não consigo encontrar nenhuma variável que contenha isso. Mas acho que deve ser mantido em algum lugar, já que o indicador é capaz de mostrar qual subvisualização da exibição de rolagem está sendo exibida no momento.

Isso está completamente oculto para nós ou há uma maneira de eu acessá-lo?

TheNeil
fonte

Respostas:

263

Não há UIScrollViewpropriedade para a página atual. Você pode calculá-lo com:

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

Se você quiser arredondar para cima ou para baixo para a página mais próxima, use:

CGFloat width = scrollView.frame.size.width;
NSInteger page = (scrollView.contentOffset.x + (0.5f * width)) / width;
AlexVogel
fonte
7
Não se esqueça de usar o UIScrollViewDelegatepara obter a página atual quando o usuário rolar!
Sam Spencer
Isso pode causar problemas ao lidar com a rotação.
Jason McCreary
adicione a versão rápida
fnc12
1
Isso nem sempre funciona, às vezes a largura do quadro está errada.
Rodrigo Ruiz
Isso nem sempre funciona. Às vezes estou obtendo a página como 0, o que está errado no meu caso.
Sneha
32

Eu realmente recomendo que você use este código

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

mas se você usar este código, sua visualização não precisa estar exatamente na página que o indexOfPage oferece. É porque eu também recomendo que você use este código apenas neste método

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

que é chamado quando seu scrollView termina de rolar e para ter o número de sua página realmente nítido

Eu recomendo que você defina seu scrollView como paged habilitado com este código

[scrollView setPagingEnabled:YES];

Então, finalmente, deve ser assim

-(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
fonte
não funciona no dispositivo iOS7 (compilado com XCODE 6.2) contentOffset.x é igual a 639 em vez de 640 (não me pergunte por que ...) quando scrollViewDidEndDecelerating. a resposta do usuário 363349 está correta: return floor ((self.contentOffset.x - pageWidth / 2) / pageWidth) + 1;
Vassily
Isso nem sempre funciona. Às vezes estou obtendo a página como 0, o que está errado no meu caso.
Sneha
30

Rapidamente, eu faria isso em extensão:

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

Depois é só ligar:

scrollView.currentPage
Andrius Steponavičius
fonte
10
Quase perfeito, tive que remover o +1 no final, já que tudo é zero com base no meu mundo
mvandillen
12

Como acima, mas como uma categoria


@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
fonte
6
Isso está exagerado, basta usar return round (self.contentOffset.x / self.frame.size.width); Muito mais simples e fácil de entender ..
Leonard Pauli
-1 @LeonardPauli. A implementação acima retorna a página que está mais de 50% visível. A implementação ingênua apenas altera o valor da página quando a subvisualização do scrollview ocupa todos os limites do scrollview.
usuário de
1
@user Primeiramente, floor () arredonda sempre para baixo, e round () arredonda para cima se a parte decimal for> = 5, senão para baixo. Com isso dito, piso (a) = redondo (a-0,5). Vamos fazer uma álgebra simples. piso ((ab / 2) / b) +1 = piso (a / b-0,5) +1 = redondo (a / b-0,5-0,5) +1 = redondo (a / b-1) +1 = redondo ( a / b). Veja! Parece que floor ((ab / 2) / b) +1 = round (a / b)! Matemágico.
Leonard Pauli
Mas sim, se eu, por algum motivo, tivesse usado chão em vez disso, você estaria perfeitamente certo! ;)
Leonard Pauli
8

Outra maneira :

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

Basta dividir o deslocamento atual pelo tamanho da página:

CGFloat pageNum = (int)(scrollView.contentOffset.x / scrollView.frame.size.width);
Aoakenfo
fonte
11
Casting para int e, em seguida, atribuindo a um float? Por que não fazer pageNum int também;)
Klaas
6

Já existem boas respostas aqui. No entanto, para cenários onde o conteúdo não se encaixa exatamente em uma página - e se, como eu, você deseja usar o resultado para um UIPageControl, então é essencial usar oceil função.

Vejamos um exemplo em que tenho "quatro e um pouco" páginas de conteúdo.

Vou basear isso no meu exemplo atual da vida real. A largura do tamanho do conteúdo é 3140 pontos. Com base no tamanho do quadro da visualização da minha coleção, a largura da página é 728.

Portanto, o número de páginas é igual a:

 3140 / 728 = 4.313 

Meu numberOfPagesvai fazer cinco anos. Quatro dos quais serão exibidos na íntegra, e o último dos quais - página cinco - irá mostrar o restante0.313 do conteúdo.

Agora, numberOfPages ser cinco significa que os índices da página serão 0, 1, 2, 3 e 4.

Quando eu deslizo para a direita, indo em direção ao deslocamento final, o scrollViewDidEndDecelerating método fornece um deslocamento X final de 2412.

Aplicando o cálculo de arredondamento:

2412 / 728 = 3.313 then rounded = 3

Isso está incorreto. A página que o usuário está visualizando por deslocamento deve ser:

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

O cálculo correto 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
fonte
4

Para o rápido, eu apenas usaria isso

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

Bastante simples, basicamente pega a posição x da scrollview, divide pela largura da scrollview e depois a arredonda.

Netuno
fonte
3

No xCode 7.x swift 2.x você pode fazer:

//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
fonte
3

A solução do Aoakenfo é incrível, esta é outra solução combinando seu código com a função scrollViewDidScroll e 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
fonte
1
Isso é ganancioso, não preguiçoso ... Também não é MVC. Uma maneira muito mais simples é invalidar a página atual na rolagem e configurá-la apenas quando for solicitada ... tudo de uma subclasse ou categoria no UIScrollView
2

Eu extraí isso de alguns de nossos aplicativos ...

- (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;
}

Fonte completa aqui


fonte
1

Você está usando um UIPageControl? Nesse caso, isso tem uma currentPagepropriedade. Do contrário, acho que você precisará calcular o índice da página a partir do deslocamento de scrollView.

Rengers
fonte
0

Se alguém está procurando uma maneira de fazer em 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 e Setter devem fornecer a você a página atual e também permitir que você role para a página especificada

soan saini
fonte
0

Extensão UIScrollView do Swift 5.1+ (omitindo a palavra-chave de retorno)

extension UIScrollView {

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