learn - Personaliza el color de texto de UIDatePicker para iOS7(al igual que Mailbox)
learn ios (5)
Estoy teniendo el dilema más frustrante. Investigué hacia arriba y hacia abajo y puedo ver claramente que Apple no quiere que manipulemos iOS 7. Bueno, quiero manipularlo. Y, el equipo de Mailbox claramente descubrió cómo hacerlo y obtener la aprobación.
Lo principal que trato de lograr es cambiar el color de la etiqueta a blanco.
Mi primer pensamiento fue que están usando un UIPickerView personalizado que solo imita a un UIDatePicker, pero simplemente no creo que este sea el caso.
Hice zoom en un pequeño fragmento y descubrí restos de un UIDatePicker normal (líneas negras) junto con el recorte en la letra "W".
Ahora he recorrido alto y bajo. Hizo algunos hackers en el tiempo de ejecución, metido en UIAppearance e incluso busqué algunas API privadas solo para ver si esto era posible.
Estuve cerca, muy cerca, pero usaba una API privada, y si se desplazaba lo suficientemente rápido, las etiquetas se volverían negras otra vez.
Estoy completamente perdido sobre cómo hacer esto sin a) romper las reglas o b) pasar innumerables horas reimplementando UIDatePicker.
Buzón, dime tus secretos! Y si alguien más tiene alguna sugerencia (y me refiero a alguna), por favor avíseme.
Además, esto es lo más cercano que he recibido:
Aquí hay un buen fragmento de trabajo. Probado en iOS 7.1 , 8.0 y 8.1 .
#if __IPHONE_OS_VERSION_MAX_ALLOWED > __IPHONE_8_1
#error "Check if this hack works on this OS"
#endif
[self.datePicker setValue:[UIColor whiteColor] forKeyPath:@"textColor"];
SEL selector = NSSelectorFromString(@"setHighlightsToday:");
NSInvocation *invocation = [NSInvocation invocationWithMethodSignature:[UIDatePicker instanceMethodSignatureForSelector:selector]];
BOOL no = NO;
[invocation setSelector:selector];
[invocation setArgument:&no atIndex:2];
[invocation invokeWithTarget:self.datePicker];
He añadido una condición simple para romper el proceso de compilación si está compilando para iOS> 8.1 , porque no puedo estar seguro de que este truco funcionará, y no quiere tener fallas en la producción debido a esto .
El selector setHighlightsToday:
se utiliza porque UIDatePicker
usa [UIColor blackColor]
de forma predeterminada para mostrar la fecha actual.
Encontré el truco que establece el color de la fuente en cualquier color y tampoco me equivoco con la etiqueta Hoy.
datePicker.setValue(UIColor.whiteColor(), forKeyPath: "textColor")
datePicker.datePickerMode = .CountDownTimer
datePicker.datePickerMode = .DateAndTime //or whatever your original mode was
Aquí está el resultado:
Y todos los créditos para esta solución van a esta publicación en otro hilo: https://.com/a/33459744/1236334
La forma segura de hacerlo es recorrer las subvistas y las subvistas de las subvistas, hasta que encuentre la clase que está buscando (en este caso, algún tipo de UILabel) y establecer manualmente las propiedades en ella.
Para encontrar el que está buscando, le sugiero que use una aplicación como rayos X o Reveal para inspeccionar la jerarquía de vistas y obtener el nombre de clase exacto, y luego:
for (UIView * subview in datePicker.subviews) {
if ([subview isKindOfClass:NSClassFromString:@"_UISomePrivateLabelSubclass"]) {
[subview setColor:...
//do interesting stuff here
}
}
Esta es una forma muy frágil de hacer las cosas, pero técnicamente nunca llama a una API privada, y no asustaría a Apple. De vuelta en iOS 5 solía hacer cosas como esta para hacer que UIAlertViews fuera más grande en iPads para tener más texto sin la vista de desplazamiento incrustada.
Puede ser necesario un montón de prueba y error, y puede que no se vea bonito, pero funcionará.
(Como dije, un tipo muy inteligente dijo: "todo el código se perderá para el compilador, como lágrimas en la lluvia").
Necesito algo similar para mi aplicación y he terminado yendo por el camino más largo. Es una verdadera lástima que no haya una manera más sencilla de cambiar a una versión de texto blanca de UIDatePicker.
El código siguiente utiliza una categoría en UILabel para forzar que el color del texto de la etiqueta sea blanco cuando el mensaje setTextColor: se envía a la etiqueta. Para no hacer esto para cada etiqueta en la aplicación, lo he filtrado para que solo se aplique si es una subvista de una clase UIDatePicker. Finalmente, algunas de las etiquetas tienen sus colores establecidos antes de que se agreguen a sus supervistas. Para atraparlos, el código anula el método willMoveToSuperview:
Es probable que sea mejor dividir el siguiente en más de una categoría, pero lo he agregado todo aquí para facilitar la publicación.
#import "UILabel+WhiteUIDatePickerLabels.h"
#import <objc/runtime.h>
@implementation UILabel (WhiteUIDatePickerLabels)
+ (void)load {
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
[self swizzleInstanceSelector:@selector(setTextColor:)
withNewSelector:@selector(swizzledSetTextColor:)];
[self swizzleInstanceSelector:@selector(willMoveToSuperview::)
withNewSelector:@selector(swizzledWillMoveToSuperview:)];
});
}
// Forces the text colour of the lable to be white only for UIDatePicker and its components
-(void) swizzledSetTextColor:(UIColor *)textColor {
if([self view:self hasSuperviewOfClass:[UIDatePicker class]] ||
[self view:self hasSuperviewOfClass:NSClassFromString(@"UIDatePickerWeekMonthDayView")] ||
[self view:self hasSuperviewOfClass:NSClassFromString(@"UIDatePickerContentView")]){
[self swizzledSetTextColor:[UIColor whiteColor]];
} else {
//Carry on with the default
[self swizzledSetTextColor:textColor];
}
}
// Some of the UILabels haven''t been added to a superview yet so listen for when they do.
- (void) swizzledWillMoveToSuperview:(UIView *)newSuperview {
[self swizzledSetTextColor:self.textColor];
[self swizzledWillMoveToSuperview:newSuperview];
}
// -- helpers --
- (BOOL) view:(UIView *) view hasSuperviewOfClass:(Class) class {
if(view.superview){
if ([view.superview isKindOfClass:class]){
return true;
}
return [self view:view.superview hasSuperviewOfClass:class];
}
return false;
}
+ (void) swizzleInstanceSelector:(SEL)originalSelector
withNewSelector:(SEL)newSelector
{
Method originalMethod = class_getInstanceMethod(self, originalSelector);
Method newMethod = class_getInstanceMethod(self, newSelector);
BOOL methodAdded = class_addMethod([self class],
originalSelector,
method_getImplementation(newMethod),
method_getTypeEncoding(newMethod));
if (methodAdded) {
class_replaceMethod([self class],
newSelector,
method_getImplementation(originalMethod),
method_getTypeEncoding(originalMethod));
} else {
method_exchangeImplementations(originalMethod, newMethod);
}
}
@end
self.birthDatePicker.setValue(UIColor.whiteColor(), forKeyPath: "textColor")
Esto funcionó para mí.