30 Nov, 2009 12:44

UIPickerView circular - "Gambiarra oficial" da Apple

UIPickerView normal

Não vou me aprofundar sobre o uso deste componente em situações normais, pois já existe documentação suficiente para isso, mas pretendo explorar uma maneira de estender seu comportamento, permitindo que a lista de opções apareça de uma maneira circular, num loop infinito.

O componente padrão, infelizmente, não possui qualquer mecanismo para viabilizar essa funcionalidade, contudo existe um outro componente, UIDatePicker, que utiliza o UIPickerView com uma lista circular para escolher dias, minutos, etc. Vendo isso, conclui: "bom, tem um jeito.. a Apple só não quer nos contar qual".

UIDatePicker com lista circular

Procurando o truque

Coloquei o UIDatePicker numa app de teste para rodar no iPhone e ativei o modo de debug para começar a destrinchar o componente. Fiz um passeio entre dezenas de views e subviews, trocando ponteiros em tempo de execução, chamando métodos de objetos que nunca teria acesso de modo normal, entre outras coisas que crianças não devem tentar em casa :) e acabei topando com a solução para o problema. E me surpreendi!

Expondo a gambiarra

O UIPickerView sempre deve ser associado a um UIPickerViewDataSouce e a um UIPickerViewDelegate que vão prover as informações necessárias para montar o componente.

Vou assumir que existe um array que será a base de dados para o componente.

NSArray *meusItens;

O UIPickerViewDataSouce possui um método que define o número de linhas (rows) que cada subcomponente do UIPickerView deverá exibir. É aí que começa o truque.

- (NSInteger)pickerView:(UIPickerView *)pickerView numberOfRowsInComponent:(NSInteger)component {
    return [meusItens count] * 10000;
}

Observe que multipliquei o numero de elementos do array por 10.000!! Sim! Este é o macete que a Apple usa para fazer uma lista "infinita". Não tem nada de infinita, mas sim uma lista suficientemente grande para que somente os usuário mais chatos curiosos consigam chegar ao fim.

Para completar o truque, a lista de 10000 x N opções deve ser exibida a partir da metade. Desta maneira, ela terá scroll "infinito" em qualquer direção. Basta colocar a linha a seguir no viewDidLoad do seu controlador, ou onde achar melhor.

[minhaPickerView selectRow:([meusItens count]*5000) inComponent:0 animated:NO];

Repare que posicionei a minhaPickerView na posição 5000 x N, ou seja, na metade da lista.

Quando for necessário mapear uma linha qualquer dentro do seu array - como na hora de definir o conteúdo de cada linha ou decidir o que fazer quando o usuário escolher uma linha - basta usar o seguinte código.

[meusItens objectAtIndex:(row % [meusItens count])];

O que eu fiz foi aplicar o operador módulo (%) sobre o número da linha usando o tamanho da lista original. O resultado será sempre um inteiro entre 0 e o tamanho da lista menos 1 - que é o necessário para acessar todos os itens do array.

Pronto! Agora você tem uma lista circular com o carimbo da Apple :)

UIPickerView com lista circular

OBS: Utilize este recurso apenas se sua lista possuir um número razoável de elementos, pois se ela tiver até 4 ou 5, um ou mais elementos aparecerão duplicados na tela - o que ficaria bem esquisito.

Bom, é isto! Espero que tenha ficado claro, mas se restar dúvida, fique a vontade para colocá-la nos comentários.