简体   繁体   English

自定义UIDatePicker for iOS7的文本颜色(就像Mailbox一样)

[英]Customize text color of UIDatePicker for iOS7 (just like Mailbox does)

I'm having the most frustrating dilemma. 我陷入了最令人沮丧的困境。 I've researched up and down and can clearly see that Apple does not want us tampering with iOS 7. Well, I want to tamper. 我上下研究过,可以清楚地看到Apple不希望我们篡改iOS 7.好吧,我想篡改。 And, the team at Mailbox clearly figured out how to do it and get approved. 而且,Mailbox的团队清楚地知道如何做到这一点并获得批准。

The main thing that I'm trying to achieve is to change the label color to white. 我想要实现的主要是将标签颜色更改为白色。

邮箱UIDatePicker

My first thought was they are using a custom UIPickerView that just mimics a UIDatePicker, but I just don't think this is the case. 我的第一个想法是他们使用的是模仿UIDatePicker的自定义UIPickerView,但我不认为是这种情况。

I zoomed in on a small fragment and discovered remnants of a normal UIDatePicker (black lines) along with clipping on the letter "W". 我放大了一个小片段,发现了正常UIDatePicker(黑线)的残余以及字母“W”上的剪辑。

邮箱UIDatePicker片段

Now I've scoured high and low. 现在我已经高高低调了。 Did some runtime hacking, messed with UIAppearance, and even dug into some private APIs just to see if this is possible. 做了一些运行时黑客攻击,与UIAppearance混淆,甚至挖到一些私有API只是为了看看这是否可行。

I got close, very close, but it used a private API, and if you scrolled fast enough the labels would turn black again. 我接近,非常接近,但它使用了私有API,如果你滚动得足够快,标签会再次变黑。

I'm completely at a loss on how to do this without a) breaking the rules or b) spending countless hours reimplementing UIDatePicker. 如果没有a)违反规则或b)花费无数小时重新实现UIDatePicker,我完全不知道如何做到这一点。

Mailbox, tell me your secrets! 邮箱,告诉我你的秘密! And if anyone else has any suggestions (and I mean any), please let me know. 如果其他人有任何建议(我的意思是任何建议),请告诉我。

Also, this is the closest I've gotten: 此外,这是我得到的最接近的:

到目前为止如此接近

I need similar for my app and have ended up going the long way round. 我需要与我的应用程序类似,并且最终走了很长一段路。 It's a real shame there isn't an easier way to simply switch to a white text version of UIDatePicker. 真的很遗憾没有一种简单的方法可以简单地切换到UIDatePicker的白色文本版本。

The code below uses a category on UILabel to force the label's text colour to be white when the setTextColor: message is sent to the label. 当setTextColor:消息发送到标签时,下面的代码使用UILabel上的类别强制标签的文本颜色为白色。 In order to not do this for every label in the app I've filtered it to only apply if it's a subview of a UIDatePicker class. 为了不对应用程序中的每个标签执行此操作,我已将其过滤为仅适用于它是UIDatePicker类的子视图。 Finally, some of the labels have their colours set before they are added to their superviews. 最后,一些标签在添加到超级视图之前已经设置了颜色。 To catch these the code overrides the willMoveToSuperview: method. 要捕获这些代码,请覆盖willMoveToSuperview:方法。

It would likely be better to split the below into more than one category but I've added it all here for ease of posting. 将下面的内容分成多个类别可能会更好,但为了便于发布,我在这里添加了所有内容。

#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

Here's a good working snippet. 这是一个很好的工作片段。 Tested on iOS 7.1 , 8.0 and 8.1 . iOS 7.1,8.08.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];

I've added a simple condition to break the compilation process if you're building for iOS > 8.1 , because I can't be sure that this hack will work, and you don't want to have any crashes in production because of this. 我已经添加了一个简单的条件来打破编译过程,如果你正在为iOS> 8.1构建,因为我不能确定这个hack是否会起作用,并且你不希望因为这个而在生产中出现任何崩溃。

The setHighlightsToday: selector is used because UIDatePicker is using [UIColor blackColor] by default to display the current date. 使用setHighlightsToday:选择器是因为UIDatePicker默认使用[UIColor blackColor]来显示当前日期。

I found the trick that set font color to any color and also dont mess up with Today label. 我找到了将字体颜色设置为任何颜色的技巧,也没有搞乱今日标签。

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

Here is the result: 结果如下:

And all the credits for this solution goes to this post in other thread: https://stackoverflow.com/a/33459744/1236334 此解决方案的所有学分都转到其他帖子的这篇文章: https//stackoverflow.com/a/33459744/1236334

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

这对我有用。

The surefire way to do this is to iterate through subviews, and subviews of subviews, until you find the class you're looking for (in this case, some kind of UILabel) and manually set properties on it. 执行此操作的可靠方法是迭代子视图和子视图的子视图,直到找到您要查找的类(在本例中为某种UILabel)并在其上手动设置属性。

To find the one you're looking for I suggest you use an app like X-ray or Reveal to inspect the view hierarchy to get the exact class name, and then: 要找到您要查找的那个,我建议您使用X-ray或Reveal等应用来检查视图层次结构以获取确切的类名,然后:


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

This is a very fragile way of doing things, but it doesn't technically ever call a private API, and it wouldn't scare Apple. 这是一种非常脆弱的做事方式,但它从技术上讲并不是一种私有API,它不会吓到Apple。 Back in iOS 5 I used to do things like this to make UIAlertViews bigger on iPads to have more text without the embedded scroll view. 回到iOS 5,我曾经做过这样的事情,让iPad上的UIAlertViews更大,以获得更多没有嵌入滚动视图的文本。

A lot of trial and error might be necessary, and it may not look pretty, but it will work. 许多试验和错误可能是必要的,它可能看起来不漂亮,但它会工作。

(As a very smart guy I know said: "all the code will be lost to the compiler, like tears in rain.") (作为一个非常聪明的家伙,我知道说:“所有的代码都将丢失给编译器,就像雨中的泪水。”)

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM