Im tratando de crear un control giratorio, básicamente un conjunto de 6 dígitos que dan vueltas y vueltas para dar el efecto de un medidor giratorio (similar a su potencia/agua metros, o tal vez una máquina de póquer, de hecho muy similar al control UIPickerView existente, pero con un aspecto completamente diferente).Dificultades principales de la animación con el control de cuadrante giratorio (muy detallado)
Hasta ahora, casi lo tengo funcionando, pero estoy en una etapa en la que la animación principal me está causando dolor.
Es bastante complejo, por lo que los fragmentos de código serían difíciles de dar una buena instantánea de lo que está sucediendo, por lo que creo que el pseudocódigo será suficiente.
En primer lugar, en términos de la configuración de vista, tengo 6 UIView
s separados (llamados NumberView1, NumberView2, etc ...), cada uno para cada número en el control.
Dentro de cada NumberViewX tengo otro UIView
, que es una vista recipiente, llamado ContainerView1, 2, etc ...
I entonces tener 10 UIImageView
s apiladas una encima de la otra en diferentes offsets y. Estas imágenes son todas 30x30 lo que lo hace agradable. 9 es primero, luego 8 en y-offset 30, luego 7 en y-offset 60, etc. ... todo el camino hasta 0 en y-offset 270.
NOTA IMPORTANTE: Mis números solo se desplazan hacia arriba
Los números representan un número de 5 puntos decimales (es decir, 2.34677) que se desplaza hacia arriba (a, por ejemplo, 2.61722).
También tengo algunos diccionarios que mantienen el valor numérico actual para cada número y los desplazamientos para cada número:
NSArray *offsets = [[NSArray alloc] initWithObjects:
[NSNumber numberWithInt:0], //9
[NSNumber numberWithInt:-30], //8
[NSNumber numberWithInt:-60], //7
[NSNumber numberWithInt:-90], //6
[NSNumber numberWithInt:-120], //5
[NSNumber numberWithInt:-150], //4
[NSNumber numberWithInt:-180], //3
[NSNumber numberWithInt:-210], //2
[NSNumber numberWithInt:-240], //1
[NSNumber numberWithInt:-270], //0
nil];
NSArray *keys = [[NSArray alloc] initWithObjects:
[NSNumber numberWithInt:9],
[NSNumber numberWithInt:8],
[NSNumber numberWithInt:7],
[NSNumber numberWithInt:6],
[NSNumber numberWithInt:5],
[NSNumber numberWithInt:4],
[NSNumber numberWithInt:3],
[NSNumber numberWithInt:2],
[NSNumber numberWithInt:1],
[NSNumber numberWithInt:0], nil];
offsetDict = [[NSDictionary alloc] initWithObjects:offsets forKeys:keys];
[currentValuesForDecimalPlace setObject:[NSNumber numberWithInt:2] forKey: [NSValue valueWithNonretainedObject: self.containerViewDollarSlot1]];
[currentValuesForDecimalPlace setObject:[NSNumber numberWithInt:8] forKey: [NSValue valueWithNonretainedObject: self.containerViewDecimalPlace1]];
[currentValuesForDecimalPlace setObject:[NSNumber numberWithInt:3] forKey: [NSValue valueWithNonretainedObject: self.containerViewDecimalPlace2]];
[currentValuesForDecimalPlace setObject:[NSNumber numberWithInt:3] forKey: [NSValue valueWithNonretainedObject: self.containerViewDecimalPlace3]];
[currentValuesForDecimalPlace setObject:[NSNumber numberWithInt:8] forKey: [NSValue valueWithNonretainedObject: self.containerViewDecimalPlace4]];
[currentValuesForDecimalPlace setObject:[NSNumber numberWithInt:5] forKey: [NSValue valueWithNonretainedObject: self.containerViewDecimalPlace5]];
ya por la lógica, comienzo a cabo el ajuste de las propiedades de capa del ContainerView ser ciertas compensaciones de Y que moverá los números actuales en sus lugares correctos, así:
self.containerViewDollarSlot1.layer.transform = CATransform3DTranslate(self.containerViewDollarSlot1.layer.transform, 0, -210, 0);
self.containerViewDecimalPlace1.layer.transform = CATransform3DTranslate(self.containerViewDecimalPlace1.layer.transform, 0, -30, 0);
self.containerViewDecimalPlace2.layer.transform = CATransform3DTranslate(self.containerViewDecimalPlace2.layer.transform, 0, -180, 0);
self.containerViewDecimalPlace3.layer.transform = CATransform3DTranslate(self.containerViewDecimalPlace3.layer.transform, 0, -180, 0);
self.containerViewDecimalPlace4.layer.transform = CATransform3DTranslate(self.containerViewDecimalPlace4.layer.transform, 0, -30, 0);
self.containerViewDecimalPlace5.layer.transform = CATransform3DTranslate(self.containerViewDecimalPlace5.layer.transform, 0, -120, 0);
que mostrará los números, 2,83385, que es un número arbitrario por el bien de pruebas.
Entonces entro en otro valor en un cuadro de texto y pulsa el botón Ir, que da inicio a la lógica de la animación, que es donde consigo las dificultades en las materias básicas de animación (como sugiere el título)
que llamo:
[self animateDecimalPlace: 0
withAnimation: self.dollarSlot1Animation
andContainerView: self.containerViewDollarSlot1];
[self animateDecimalPlace: 1
withAnimation: self.decimalPlace1Animation
andContainerView: self.containerViewDecimalPlace1];
//etc... for all 6 numbers
donde dollarSlot1Animation es un Ivar CABasicAnimation
se define el método siguiente:
- (void) animateDecimalPlace: (int) decimalIndex withAnimation: (CABasicAnimation*)animation andContainerView: (UIView*) containerView{
NSRange decimalRange = {decimalIndex == 0 ? 0 : 2,
decimalIndex == 0 ? 1 : decimalIndex};
double diff = 0;
if (decimalIndex == 0)
{
int decimalPartTarget = [[[NSString stringWithFormat:@"%f", targetNumber] substringWithRange: decimalRange] intValue];
int decimalPartCurrent = [[[NSString stringWithFormat:@"%f", currentValue] substringWithRange: decimalRange] intValue];
diff = decimalPartTarget - decimalPartCurrent;
}
else {
double fullDiff = targetNumber - currentValue;
diff = [[[NSString stringWithFormat:@"%f", fullDiff] substringWithRange: decimalRange] doubleValue];
}
animation.removedOnCompletion = NO;
animation.fillMode = kCAFillModeRemoved;
animation.duration = 5.0;
NSNumber *n = [currentValuesForDecimalPlace objectForKey:[NSValue valueWithNonretainedObject: containerView]];
NSNumber *offset = (NSNumber*)[offsetDict objectForKey: n];
int rotations = [self setupNumberForAnimation: diff decimalIndex: decimalIndex forContainer: containerView];
int finalOffset = (rotations*30)+([offset intValue]);
CATransform3D translation = CATransform3DMakeTranslation(0, finalOffset, 0);
animation.fromValue = [NSValue valueWithCATransform3D:containerView.layer.transform];
animation.toValue = [NSValue valueWithCATransform3D:translation];
animation.delegate = self;
[containerView.layer addAnimation: animation forKey: [NSString stringWithFormat:@"%i", decimalIndex] ];
}
Como puede ver (o tal vez no :)) estoy tratando cada número básicamente independiente, y diciéndole que se traduzca a una nueva posición Y, pero puede haber notado un método llamado setupNumberForAnimation
que es otro método grande que agrega dinámicamente más UIImageView
s al contenedor UIView anterior los 10 mosaicos iniciales de la imagen.
Por ejemplo, hay 10 fichas para comenzar, si quiero desplazar el dial UP 21 puntos (pasando de 3 a 24, por ejemplo) necesitaría agregar 15 números nuevos por encima de 9, luego animar el traducción de la vista del contenedor hasta la parte superior del mosaico de la imagen.
Después de que el desplazamiento esté listo, elimino los UIImageView
s dinámicamente agregados y vuelva a colocar la vista y del desplazamiento de la vista del contenedor a un valor entre 0 y -270 (esencialmente terminando en el mismo número, pero quitando todas las -imágenes de imagen necesarias).
Esto da la animación suave que im después. Y funciona. Confía en mí :)
Mi problema es doble, en primer lugar cuando la animación se detiene Núcleo de animación revierte los cambios de animaciones a la capa porque he configurado animation.fillMode = kCAFillModeRemoved;
No pude entender cómo, una vez completadas las animaciones, establecer la capa del contenedor y offset, sé que suena extraño, pero si tengo la propiedad fillMode establecida en kCAFillModeForwards, nada de lo que intento parece tener un efecto en la capa.
En segundo lugar, cuando la animación se detiene y el cambio se revierte, hay un pequeño parpadeo entre cuando la animación revierte la traducción y cuando lo configuro de nuevo, no puedo encontrar la manera de evitarlo.
Sé que hay un montón de detalles y especificidad aquí, pero cualquier ayuda o idea sobre cómo lograr esto sería muy apreciada.
Muchas gracias
Es mejor que ser vago (como este comentario). – BoltClock
Una tesis a juzgar por un profesor;) –
Gracias por la "ayuda" ... Sé que es una publicación detallada, pero estoy abierto a otras ideas también, estoy feliz de eliminar mi implementación por completo – Mark