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

Posted

技术标签:

【中文标题】为 iOS7 自定义 UIDatePicker 的文本颜色(就像邮箱一样)【英文标题】:Customize text color of UIDatePicker for iOS7 (just like Mailbox does) 【发布时间】:2013-12-09 11:30:55 【问题描述】:

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

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

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

我放大了一个小片段,发现了一个正常的 UIDatePicker(黑线)的残留物以及字母“W”上的剪裁。

现在我已经高高在上。做了一些运行时黑客,弄乱了 UIAppearance,甚至挖掘了一些私有 API 只是为了看看这是否可能。

我接近了,非常接近,但它使用了私有 API,如果你滚动得足够快,标签会再次变黑。

我完全不知道如何在不违反规则或 b) 花费无数小时重新实现 UIDatePicker 的情况下执行此操作。

邮箱,告诉我你的秘密!如果其他人有任何建议(我的意思是任何建议),请告诉我。

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

【问题讨论】:

你有什么问题? UIDatePicker 与标准 UIDatePicker 有何不同?图片是来自您的应用还是其他应用? 我将进行编辑以澄清这一点。感谢您的标注! 【参考方案1】:

我的应用需要类似的东西,并且最终走了很长一段路。真的很遗憾,没有更简单的方法可以简单地切换到 UIDatePicker 的白色文本版本。

当 setTextColor: 消息发送到标签时,下面的代码使用 UILabel 上的类别来强制标签的文本颜色为白色。为了不对应用程序中的每个标签执行此操作,我将其过滤为仅在它是 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

【讨论】:

天才感谢! Apple 是否会批准这一点? @Gal 这获得批准了吗? 我会自己尝试,我的申请现在处于审核级别。 是否有任何应用通过这种技术获得批准? 该申请自 2014 年 12 月起获得苹果批准 :)【参考方案2】:

这是一个很好的工作 sn-p。在 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];

如果您正在为 iOS > 8.1 构建,我添加了一个简单的条件来中断编译过程,因为我不能确定这个 hack 是否有效,而您不知道因此希望在生产中发生任何崩溃。

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

【讨论】:

只有几行代码,这必须被接受为答案,太棒了,非常感谢。 效果很好!但在 iOS 8.1 中,那一年的文本颜色没有改变。请给我同样的建议。 嗨,如果我使用此代码,“今天”标签将更改为日期(例如 4 月 10 日星期三)。小伙伴们有没有同样的经历呢?除了这个问题,其他一切都很酷。 在 swift 中:picker.sendAction("setHighlightsToday:", to: nil, forEvent: nil)【参考方案3】:

我发现了将字体颜色设置为任何颜色并且不会弄乱 Today 标签的技巧。

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

结果如下:

此解决方案的所有功劳都转到其他线程中的此帖子: https://***.com/a/33459744/1236334

【讨论】:

这是一个比使用 setHighlightsToday 更好的解决方案:有两个原因......它不会用日期替换“Today”,并且它不会在 Swift 2.2 中产生编译器警告【参考方案4】:
self.birthDatePicker.setValue(UIColor.whiteColor(), forKeyPath: "textColor")

这对我有用。

【讨论】:

知道其他标签键路径是什么吗? 在swift中可以取消今天的文字颜色:picker.sendAction("setHighlightsToday:", to: nil, forEvent: nil) 有趣的是,这不适用于属性的 didSet,但可以在 viewDidLoad 下工作。【参考方案5】:

执行此操作的可靠方法是遍历子视图和子视图的子视图,直到找到要查找的类(在本例中为某种 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 中,我曾经做过这样的事情,以使 iPad 上的 UIAlertViews 更大,以便在没有嵌入滚动视图的情况下拥有更多文本。

可能需要进行大量的试验和错误,并且可能看起来不漂亮,但它会起作用。

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

【讨论】:

我试过这个,但不幸的是,私有类 _UIDatePickerView (github.com/nst/iOS-Runtime-Headers/blob/master/Frameworks/…) 在重用视图方面使用了类似于 UITableView 的东西。因此,在您创建视图并开始滚动之后,您会得到到处都是 UILabel 的混乱。看看这个看看所有的混乱:blog.ittybittyapps.com/blog/2013/09/20/…

以上是关于为 iOS7 自定义 UIDatePicker 的文本颜色(就像邮箱一样)的主要内容,如果未能解决你的问题,请参考以下文章

UIDatePicker 的自定义

使用UIAppearance自定义iOS UIDatepicker

如何创建自定义 UIDatePicker 控件

自定义 UIPickerView 和 UIDatePicker,更扁平的设计 [关闭]

在iOS 12中的UIDatePicker中自定义背景和文本颜色

带有自定义日期的 UIPickerView