2011-03-08 12 views
7

Tengo un UIPickerView con celdas personalizadas. Para cada momento, me gustaría saber qué celda está en el centro (detrás del indicador de selección tintado). El método delegado UIPickerViewPosición de lectura de PickerView mientras se desplaza

- (void)pickerView:(UIPickerView *)pickerView didSelectRow:(NSInteger)row inComponent:(NSInteger)component 

proporciona esta información, pero solo después de que se haya detenido la vista del selector. Lo que estoy buscando es una forma de recuperar la celda actualmente "seleccionada" mientras la vista del seleccionador todavía está girando y aún no se ha detenido.

Como solución, he tratado de pasar por MVA y registrarse para ver los cambios de cada célula:

- (UIView *)pickerView:(UIPickerView *)pickerView viewForRow:(NSInteger)row forComponent:(NSInteger)component reusingView:(UIView *)view { 
    . 
    . 
[cell addObserver:self forKeyPath:@"frame" options:NSKeyValueObservingOptionOld|NSKeyValueObservingOptionNew context:nil]; 
} 

hago recibir devoluciones de llamada a observeValueForKeyPath: ofObject: el cambio: contexto :, sin embargo, no importa si me desplazar la vista selector hacia arriba o hacia abajo, los valores recibidos parecen ser siempre la misma:

2011-03-09 08:00:34.429 Project[35069:207] Frame: x=2.00, y=-13.00 
2011-03-09 08:00:34.430 Project[35069:207] Location: x=4.00, y=-26.00 
2011-03-09 08:00:34.430 Project[35069:207] Change: { 
    kind = 1; 
    new = "NSRect: {{2, -13}, {118, 70}}"; 
    old = "NSRect: {{2, -13}, {118, 70}}"; 
} 
2011-03-09 08:00:34.431 Project[35069:207] Frame: x=2.00, y=-13.00 
2011-03-09 08:00:34.431 Project[35069:207] Location: x=4.00, y=-26.00 
2011-03-09 08:00:34.432 Project[35069:207] Change: { 
    kind = 1; 
    new = "NSRect: {{2, -13}, {118, 70}}"; 
    old = "NSRect: {{2, -13}, {118, 70}}"; 

(Location coordinates are in window frame) 

Cualquier otra idea lo que podría tratar de conseguir ese valor?

Respuesta

2

Puede usar el método de su selector de selectores -pickerView: titleForRow: forComponent: para tener una idea bastante clara de dónde está la rueda del selector. A medida que se desplaza en una dirección u otra, el selector le pedirá a su delegado el título (o vista) de una fila. El número de filas entre el "centro" de la rueda y la fila que solicita el selector depende de la altura de la fila, pero es probable que sepa de qué se trata.

Tendrás que experimentar un poco para hacerlo bien. El selector parece pedir una o dos filas que aún no son visibles, tal vez para mantener el desplazamiento suave. En mi prueba con un selector que muestra 5 filas, parece haber una diferencia de 3 filas entre la fila que el seleccionador pedía y el centro. Obviamente, también deberá hacer un seguimiento de la dirección de rotación (hacia arriba o hacia abajo), y no descubrirá si se seleccionan las primeras o las últimas dos o tres filas hasta que se llame a su -pickerView: didSelectRow: inComponent :.

+2

Vi esta idea en otro lado, pero parece un poco insegura. Nunca se sabe cuántas vistas estarán exactamente precargadas. El número puede variar en las diferentes versiones de iOS, tal vez también dependiendo de la disponibilidad de la memoria del dispositivo. He buscado en la documentación, pero no pude encontrar nada especificado al respecto. –

+0

Definitivamente no hay garantías, y como mencioné anteriormente, la técnica no está exenta de defectos. Recomiendo absolutamente pruebas minuciosas. Sin embargo, a menos que tenga su propia vista de selector, creo que es lo más cercano que recibirá la notificación en tiempo real de los cambios al selector. – Caleb

+1

Hago esto, donde compruebo que cada cambio es consecutivo, como pickerView: titleForRow: forComponent: preselecciona filas de forma aleatoria, por lo que mantengo la fila anterior en algún lugar y actúo solo si es una arriba o una abajo: ~ if (row == self.oldrow + 1 || row == self.oldrow - 1) ~ –

0

Creo que esto es interesante. Quería hacer algo similar con UIPicker, pero aún no he investigado mucho.

UIDatePicker realmente hace esto, puede arrastrar el tiempo alrededor del mediodía y va a cambiar de AM/PM a pesar de que el dedo no se ha levantado de la pantalla (que no debería haber llamado "didSelectRow" aún).

UIDatePicker en realidad subclases de UIControl, en lugar de UIView como UIPickerView. Entonces, UIDatePicker probablemente está observando todos los UIControlEvents para hacer esto.

de Observación -pickerView: titleForRow: forComponent probablemente funciona por ahora, pero si cambia el comportamiento posterior (es decir, el comportamiento de almacenamiento en caché, es decir) se cambia, esto se romperá ...

Una sugerencia es tratar de MVA en la propiedad del centro , en lugar de marco.

Edit1: Por cierto, ¿cómo se ve el método observeValueForKeyPath?

Edit2: Tras nuevas investigaciones, parece que la mayoría de UIKit no es compatible con KVO.
Ver esta respuesta - Key value Observing during UIView Animations

Por lo tanto, parece que la única opción es mantener la polarización para el valor de la vista cuando es visible. ¿Qué tal un forloop y un bastidor polar/propiedad central siempre que esté a la vista?

0

El marco no cambia porque la celda no se está moviendo. Una de sus supervistas es, y la célula se lleva consigo. Para averiguar la celda de coordenada en el padre UIPickerView, intente esto:

CGRect theApparentRect = [theCell convertRect: theCell.bounds toView: thePicker]; 

El rectángulo resultante estará en el sistema de coordenadas de thePicker, y luego se puede averiguar si está en el medio con la siguiente prueba:

CGPoint middleOfThePicker = CGPointMake 
(
    CGRectGetMidX(thePicker.bounds), 
    CGRectGetMidY(thePicker.bounds) 
); 
Boolean isInMiddle = CGRectContainsPoint(theApparentRect, middleOfThePicker); 
+0

Ya estoy haciendo esto con el origen del fotograma. ¿No crees que hay alguna diferencia si transformo los límites o el origen del marco? –

+0

No, aunque el origen de la celda puede o no alinearse con los límites visibles de la vista del contenedor. Pruebe con el rect completo y vea? –

0

es sólo una idea rápida, pero se puede añadir un UIScrollView (transparente con un contentView que es tan alto como el número de componentes.) sobre el UIPickerView.

A continuación, escuche los métodos UIScrollViewDelegate para obtener los datos de desplazamiento en tiempo real que necesita.

La parte engañosa pasaría los eventos táctiles del desplazador al selector para que actuara como se esperaba.

0

El problema que tiene con UIPickerView es que la vista que está configurando para las celdas en realidad son subViews. UIPickerView está creado a partir de varias imageViews, una TableView y una línea de selección. La vista que proporciona al usar viewForRow se inserta como subViews de las celdas de tableView y para que su marco nunca se modifique. El único marco que cambia es el marco de la celda real de tableView, a la cual, por supuesto, no tiene acceso.

Una posible solución es simplemente reemplazar el tableView de UIPickerView con el suyo.

Puede hacer esto estableciendo el número de filas para el UIPickerView en 0 y coloque un tableView transparente sobre el UIPickerView. Su tableView contendrá las celdas reales, y dado que UITableView hereda de UIScrollView, puede obtener eventos sobre el desplazamiento y simplemente verificar qué UITableViewCell se encuentra actualmente en la línea de selección.

2

Creo
- (UIView *)pickerView:(UIPickerView *)pickerView viewForRow:(NSInteger)row forComponent:(NSInteger)component reusingView:(UIView *)view
Con
[pickerView selectedRowInComponent:0]);
es exactamente lo que quiere. :)

Cuestiones relacionadas