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

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/20181225/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-30 22:30:01  来源:igfitidea点击:

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

iosuikituipickerviewuidatepickeruiappearance

提问by rnystrom

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. And, the team at Mailbox clearly figured out how to do it and get approved.

我遇到了最令人沮丧的两难境地。我已经上下研究了,可以清楚地看到Apple不希望我们篡改iOS 7。好吧,我想篡改。而且,Mailbox 的团队清楚地知道如何做到这一点并获得批准。

The main thing that I'm trying to achieve is to change the label color to white.

我要实现的主要目标是将标签颜色更改为白色。

Mailbox UIDatePicker

邮箱 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.

我的第一个想法是他们正在使用一个自定义的 UIPickerView,它只是模仿 UIDatePicker,但我认为情况并非如此。

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”上的剪裁。

Mailbox UIDatePicker fragments

Mailbox UIDatePicker fragments

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.

我完全不知道如何在不违反规则或 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:

此外,这是我得到的最接近的:

So close yet so far

So close yet so far

回答by Sig

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. 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. 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.

当 setTextColor: 消息发送到标签时,下面的代码使用 UILabel 上的类别强制标签的文本颜色为白色。为了不对应用程序中的每个标签执行此操作,我将其过滤为仅在它是 UIDatePicker 类的子视图时才应用。最后,一些标签在被添加到它们的超级视图之前设置了它们的颜色。为了捕捉这些,代码覆盖了 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

回答by arturgrigor

Here's a good working snippet. Tested on iOS 7.1, 8.0and 8.1.

这是一个很好的工作片段。测试上的iOS 7.18.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 UIDatePickeris using [UIColor blackColor]by default to display the current date.

使用setHighlightsToday:选择器是因为默认情况下UIDatePicker使用[UIColor blackColor]它来显示当前日期。

回答by Klemen

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

回答by fnc12

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

This worked for me.

这对我有用。

回答by Swizzlr

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. 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.

这是一种非常脆弱的做事方式,但从技术上讲,它永远不会调用私有 API,也不会吓到 Apple。在 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.")

(正如我认识的一个非常聪明的人所说:“所有代码都会丢失给编译器,就像雨中的眼泪。”)