Подтвердить что ты не робот

Настроить цвет текста UIDatePicker для iOS7 (как и в случае с почтовым ящиком)

У меня самая неприятная дилемма. Я исследовал вверх и вниз и могу ясно видеть, что Apple не хочет, чтобы мы подделывали iOS 7. Ну, я хочу вмешаться. И команда в Mailbox ясно поняла, как это сделать и получить одобрение.

Главное, что я пытаюсь добиться, - изменить цвет ярлыка на белый.

Mailbox UIDatePicker

Моя первая мысль заключалась в том, что они используют пользовательский UIPickerView, который просто имитирует UIDatePicker, но я просто не думаю, что это так.

Я увеличил малый фрагмент и обнаружил остатки обычного UIDatePicker (черные линии) вместе с отсечением на букву "W".

Mailbox UIDatePicker fragments

Теперь я пробирался высоко и низко. Произошел какой-то хакерский хакер, запутался в UIAppearance и даже выкопал некоторые частные API, чтобы убедиться, что это возможно.

У меня был близкий, очень близкий, но он использовал частный API, и если вы прокручиваете достаточно быстро, ярлыки снова станут черными.

Я полностью в недоумении о том, как это сделать, не нарушая правил или б) потратив бесчисленные часы на повторную реализацию UIDatePicker.

Почтовый ящик, расскажи мне свои секреты! И если у кого-нибудь есть предложения (и я имею в виду любые), пожалуйста, дайте мне знать.

Кроме того, это ближайший я получил:

So close yet so far

4b9b3361

Ответ 1

Мне нужно подобное для моего приложения и закончилось тем, что продолжалось. Это настоящий позор, когда нет простого способа перейти к белой текстовой версии UIDatePicker.

В приведенном ниже коде используется категория на UILabel, чтобы заставить цвет текста ярлыка быть белым, когда сообщение setTextColor: отправлено на метку. Чтобы не делать этого для каждого ярлыка в приложении, я отфильтровал его, чтобы применять его только в том случае, если это подкласс класса UIDatePicker. Наконец, некоторые из этикеток имеют свои цвета, установленные до их добавления в свои супервизоры. Чтобы поймать их, код переопределяет метод willMoveToSuperview:.

Скорее всего, лучше разбить нижеследующее на несколько категорий, но я добавил все это для удобства размещения.

#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

Ответ 2

Вот хороший рабочий фрагмент. Протестировано на iOS 7.1, 8.0 и 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];

Я добавил простое условие для разрыва процесса компиляции, если вы создаете для iOS > 8.1, потому что я не могу быть уверен, что этот хак будет работать, а вы не из-за этого вы хотите иметь какие-либо сбои в производстве.

Селектор setHighlightsToday: используется, поскольку UIDatePicker использует [UIColor blackColor] по умолчанию для отображения текущей даты.

Ответ 3

Я нашел трюк, который задал цвет шрифта любому цвету, а также не испортил ярлык Today.

datePicker.setValue(UIColor.whiteColor(), forKeyPath: "textColor")
datePicker.datePickerMode = .CountDownTimer
datePicker.datePickerMode = .DateAndTime //or whatever your original mode was

Вот результат:

rNJe7.png

И все кредиты для этого решения идут на этот пост в другой теме: fooobar.com/questions/147895/...

Ответ 4

self.birthDatePicker.setValue(UIColor.whiteColor(), forKeyPath: "textColor")

Это сработало для меня.

Ответ 5

Верный способ сделать это - итерация через subviews и subviews subviews, пока вы не найдете класс, который вы ищете (в данном случае, какой-то UILabel) и вручную установите на нем свойства.

Чтобы найти тот, который вы ищете, я предлагаю вам использовать приложение, такое как X-ray или Reveal, для проверки иерархии представлений, чтобы получить точное имя класса, а затем:


for (UIView * subview in datePicker.subviews) {
    if ([subview isKindOfClass:NSClassFromString:@"_UISomePrivateLabelSubclass"]) {
        [subview setColor:...
        //do interesting stuff here
    }
}

Это очень хрупкий способ делать что-то, но технически никогда не называют частный API, и это не пугает Apple. Назад в iOS 5 Я делал такие вещи, чтобы сделать UIAlertViews больше на iPads, чтобы иметь больше текста без встроенного представления прокрутки.

Может потребоваться много проб и ошибок, и может показаться не очень красивым, но оно будет работать.

(Как очень умный парень, которого я знаю, сказал: "весь код будет потерян для компилятора, например, слезы в дождь".)