2012-05-30 32 views
21

He echado un vistazo a esta pregunta, pero todavía no estoy seguro de si es posible o no. Esencialmente, lo que quiero hacer es crear un UIPickerView que sea continuo en el sentido de que puedes girarlo para siempre y nunca llegarás al final (ya que el último valor va seguido del primer valor).¿Cómo hacer un UIPickerView circular (iPhone/iPad)?

He echado un vistazo en línea y parece haber una gran variedad de hacks para lograr el efecto deseado. Sin embargo, muchas de estas soluciones parecen aumentar el número de filas en el UIPickerView para engañar al usuario haciéndole creer que el UIPickerView es continuo (sin embargo, en realidad si seguían desplazándose, eventualmente llegarían al final).

Lo que busco es una forma de crear un UIPickerView que sea genuinamente infinito en el sentido de que nunca llegarás al final si sigues desplazándote durante días, semanas, meses o años. No me importa demasiado si la solución es un hack ya que entiendo que Apple no ha proporcionado una forma de lograr el efecto hasta el momento.

Por favor alguien puede aconsejarme sobre una forma de hacer esto (o apuntarme en la dirección correcta al menos)?

Respuesta

4

realmente creo, que el único truco que puede hacer con UIPickerView nativa se describe aquí:

How do you make an UIPickerView component wrap around?

La otra manera haga que realmente selector de bucle es implementar por sí mismo.

Vi selectores que se implementaron con cocos2d, es decir, basado en OpenGL. Creo que puedes intentar hacerlo usando UIKit si realmente lo necesitas.

O simplemente olvídate y crea un selector con filas NSIntegerMax con contenido repetible. Creo que nadie lo girará hasta el final.

+0

Poner NSIntegerMax generalmente bloqueará el programa. Siento que la respuesta de Olie es mejor y más razonable en caso de usabilidad y memoria. –

0

Hm .. He estado mirando a mi alrededor, y hay un par de enlaces a algunas posibilidades, la más destacada es esta: The Abusive Pickerview, la idea básica es que llene el pickerview con 3 conjuntos de sus datos y inicio y el centro establecido. Cada vez que el usuario se desplaza al centro de cualquiera de los conjuntos superior e inferior, ¡establece el valor de la fila nuevamente en el centro del conjunto central! Parece ser más genuino que hacer una lista realmente larga que creará la ilusión del infinito. ¡Esta solución puede ser la más efectiva y simple para resolver el problema de la vista infinita! Espero que esto haya ayudado!

+0

Generalmente, no debe copiar y pegar sus respuestas de otras publicaciones http://stackoverflow.com/questions/10815435/how-to-make-a-circular-uipickerview-iphone-ipad – pasawaya

+0

Hm .. No lo hice En realidad, veo esta publicación ... – wayway

2

Es posible. Aquí sabrás como podrás hacerlo. Primero configura un temporizador. Supongamos int maxNumber es una variable de instancia establecida en algún valor arbitrario.

- (void) viewWillAppear:(BOOL)animated{ 
    [super viewWillAppear:animated]; 
    [self.timer invalidate]; 
    self.timer = [NSTimer scheduledTimerWithTimeInterval:0.01 target:self selector:@selector(timerFireMethod:) userInfo:nil repeats:YES]; 

} 

- (void) viewWillDisappear:(BOOL)animated{ 
    [self.timer invalidate]; 
    [super viewWillDisappear:animated]; 
} 

- (void)viewDidLoad 
{ 
[super viewDidLoad]; 
// Do any additional setup after loading the view, typically from a nib. 
[self.infinitePickerView selectRow:(int)maxNumber*5 inComponent:0 animated:YES]; 
} 

En el cheque método de temporizador incendio si cualquiera de la vista 'borde' de su UIPickerView están mostrando.

- (void)timerFireMethod:(NSTimer*)theTimer{ 
int rowSelected = [self.infinitePickerView selectedRowInComponent:0];  
for (int i=0; i<= 20; i++) { 
    UIView * viewBelow = [self.infinitePickerView viewForRow:i forComponent:0]; 
    UIView * viewAbove = [self.infinitePickerView viewForRow:maxNumber*10-20+i forComponent:0]; 
    if(viewBelow!=nil || viewAbove!=nil){ 
     int middlePosition = maxNumber * 5 + (rowSelected % maxNumber); 
     [self.infinitePickerView selectRow:middlePosition inComponent:0 animated:NO]; 
     break; 
    } 
} 
} 

Nota esto funciona porque [self.infinitePickerView viewForRow:i forComponent:0]; devuelve un UIView sólo si es visible.

Por supuesto, su UIPickerViewDelegate debe usar algo así como

- (NSInteger)pickerView:(UIPickerView *)pickerView numberOfRowsInComponent:(NSInteger)component{ 
    return maxNumber * 10; //returning a large number 
} 

//You cannot use this method 
/* 
- (NSString *)pickerView:(UIPickerView *)pickerView titleForRow:(NSInteger)row forComponent:(NSInteger)component{} 
You have to use the method below in lieu of it 
*/ 

- (UIView *)pickerView:(UIPickerView *)pickerView viewForRow:(NSInteger)row forComponent:(NSInteger)component reusingView:(UIView *)view{ 

UILabel * label; 

if (!view) { 
    label = [[UILabel alloc] initWithFrame:CGRectMake(0, 0, self.infinitePickerView.bounds.size.width, 30)]; 
}else { 
    label = (UILabel *) view;  
} 
[label setText:[NSString stringWithFormat:@" %d", row % maxNumber]]; 
return label; 
} 

Hope esto funciona !! :) ¡Buena suerte!

+0

parece un buen truco. @The Chimp loco nos dice si funciona. –

3

Encuentra la clase personalizada UIPickerView que funciona muy bien y es muy fácil de implementar here

0

Me parece que las soluciones que requieren grandes cantidades de datos pueden rellenar en el pickerView son un desperdicio. La siguiente solución usa inteligencia en lugar de memoria.

Las únicas filas que necesitan rellenarse son las filas visibles en la vista y la fila inmediatamente anterior a la primera y la fila inmediatamente posterior a la última. Cuando el usuario desplaza un componente, se llama a pickerView: titleForRow: forComponent: para cada fila que se desplaza.

Así que la solución es actualizar los datos en pickerView: titleForRow: forComponent: y luego llamar al método apropiado para volver a cargar los datos para que estén allí cuando la vista picker se desplaza una marca más.

2

No hay un selector nativo que envuelve Puede falsa esto algo en este sentido (no como iOS7.1 de todos modos.):

NSArray *picks = @[ @"zero", @"one", @"two", @"three" ]; // 4 entries 

// ... 

- (NSInteger)pickerView:(UIPickerView *)pickerView 
numberOfRowsInComponent:(NSInteger)component 
{ 
    return (3 * [picks count]); // we're very tricky, displaying only 
           // ...the SECOND set of entries, to 
           // ... give the impression of wrap-around 
} 

// ... 

- (NSString *)pickerView:(UIPickerView *)pickerView 
      titleForRow:(NSInteger)row 
      forComponent:(NSInteger)component 
{ 
    // All "3" sets of entries have the same values; 
    // this is what gives the appearance of wrap-around. 
    int titleRow = row % [picks count]; 
    return [picks objectAtIndex: titleRow]; 
} 

// ... 

- (void)pickerView:(UIPickerView *)pickerView 
     didSelectRow:(NSInteger)row 
     inComponent:(NSInteger)component 
{ 
    // If the wheel turns to outside our 2nd-set range, 
    // ...set it to the matching item in the 2nd set. 
    // In this way, we always display what looks like a wrap-around. 
    int count = [picks count]; 
    if ((row < count) 
    || (row > (count * 2)) 
    { 
     [pickerView selectRow: (row % count) inComponent: component animated: NO]; 
    } 
} 

Vas a tener que modificar y ajustar para adaptarse a su necesidades, por supuesto, pero esta es la esencia básica de la misma.

¡Buena suerte!

0

Sé que es una vieja pregunta, pero acabo de encontrarlo ya que la estoy implementando en mi propio proyecto.

Simplemente utilice el método de Morion de una gran cantidad de elementos con contenido repetitivo, luego, cada vez que deje de desplazarse, restablezca la fila. La única forma en que alguien descubrirá que ha engañado es si se desplaza continuamente sin interrupción hasta que se detenga, sin llamar a la función didSelectRow. ¡Tomaría algo de dedicación!

Independientemente de cómo lo hace, me parece que va a sentir un poco hacky, & este debe ser el truco más fácil ...

0

he hecho un tableView cíclico basado en UIScrollView. Y basado en este tableView, reimpleto UIPickerView. Puede que te interese esto. Y esta vista del seleccionador tiene toda la función que UIPickerView, pero también ofrece muchas características nuevas, y esta vista del selector personalizada es mucho más fácil.

https://github.com/danleechina/DLPickerView

Y ser conscientes de que este desplazamiento DLPickerView cíclicamente es realmente Desplazamiento cíclicamente. Toda la magia sucedió debido a otra clase DLTableView.

0

que utilizan pickerView de selección para crear una circular: solución muy simple

import UIKit 
    class ViewController:   
UIViewController,UIPickerViewDelegate,UIPickerViewDataSource 
{ 
@IBOutlet weak var picker: UIPickerView! 
@IBOutlet weak var myLabel: UILabel! 

let numbers = [0,1,2,3,4,5,6,7,8,9] 

override func viewDidLoad() 
{ 
    super.viewDidLoad() 
    // A.Select Second Row 
    picker.selectRow(1, inComponent: 0, animated: false) 
} 
func numberOfComponents(in pickerView: UIPickerView) -> Int 
{ 
    return 1 
} 
func pickerView(_ pickerView: UIPickerView, numberOfRowsInComponent component: Int) -> Int 
{ 
    //B. Add 2 rows to your array count 
    return numbers.count + 2 
} 
func pickerView(_ pickerView: UIPickerView, titleForRow row: Int, forComponent component: Int) -> String? 
{ 
    var rowTitle = "" 
    switch row 
    { 
    case 0: 
     // C. Set first row title to last component of the array. 
     // This row is not visible to the user as it is hidden by the   

     //selection in ViewDidLoad 
     rowTitle = "\(numbers.last!)" 
    case numbers.count + 1: 
     //D. Set last row title to first array component 
     rowTitle = "\(numbers.first!)" 
    default: 
     // E. Remember [row - 1] to avoid errors 
     rowTitle = "\(numbers[row - 1])" 
    } 
    return rowTitle 
} 
func pickerView(_ pickerView: UIPickerView, didSelectRow row: Int, inComponent component: Int) 
{ 
    var theText = "" 
    switch row 
    { 
    case 0: 
     //F. Select Row at array count to load the last row 
     pickerView.selectRow(numbers.count , inComponent: 0, animated: false) 
     theText = = "\(numbers.last!)" 
    case numbers.count + 1: 
    //G. This Selection will set the picker to initial state 
     pickerView.selectRow(1, inComponent: 0, animated: false) 
     theText = "\(numbers.first!)" 
    default: 
     theText = "\(numbers[row - 1])" 
    } 
    myLabel.text = theText 

} 

    } 
0

A que hará que u piensa que no hay final de la vista selector, por la escala de la matriz y hacer que el módulo recoger la correspondido elemento de la matriz

override func viewDidLoad(){ 
    super.viewDidLoad() 
    self.yourArray.selectRow((yourArray.count*100)/2, inComponent: 0, animated: false) 
} 

func pickerView(_ pickerView: UIPickerView, numberOfRowaInComponent component: Int) -> Int{ 
    return yourArray.count*100 
} 

func pickerView(_ pickerView: UIPickerView, titleForRow row: Int, forComponent component: Int)->String{ 
    return yourArray[row % yourArray.count] 
}