Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/ios/94.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
为iOS7自定义UIDatePicker的文本颜色(就像邮箱一样)_Ios_Uikit_Uipickerview_Uidatepicker_Uiappearance - Fatal编程技术网

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

为iOS7自定义UIDatePicker的文本颜色(就像邮箱一样),ios,uikit,uipickerview,uidatepicker,uiappearance,Ios,Uikit,Uipickerview,Uidatepicker,Uiappearance,我面临着最令人沮丧的困境。我上下研究过,可以清楚地看到苹果不希望我们篡改iOS7。嗯,我想篡改一下。而且,邮箱的团队清楚地知道了如何做到这一点,并获得了批准 我试图实现的主要目标是将标签颜色更改为白色 我的第一个想法是,他们正在使用一个定制的UIPickerView,它只是模仿UIDatePicker,但我认为情况并非如此 我放大了一个小片段,发现了一个普通的UIDatePicker(黑线)的残余部分以及字母“W”的剪辑 现在我到处都找遍了。进行了一些运行时黑客攻击,搞乱了UI外观,甚至挖掘

我面临着最令人沮丧的困境。我上下研究过,可以清楚地看到苹果不希望我们篡改iOS7。嗯,我想篡改一下。而且,邮箱的团队清楚地知道了如何做到这一点,并获得了批准

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

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

我放大了一个小片段,发现了一个普通的UIDatePicker(黑线)的残余部分以及字母“W”的剪辑

现在我到处都找遍了。进行了一些运行时黑客攻击,搞乱了UI外观,甚至挖掘了一些私有API,只是为了看看这是否可行

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

我完全不知道如何做到这一点,而不a)违反规则或b)花费无数时间重新实现UIDatePicker

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

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


实现这一点的可靠方法是迭代子视图和子视图的子视图,直到找到要查找的类(在本例中是某种UILabel)并手动设置其属性

要找到您要查找的类名,我建议您使用X-ray或Reveal等应用程序检查视图层次结构,以获得准确的类名,然后:


for (UIView * subview in datePicker.subviews) {
    if ([subview isKindOfClass:NSClassFromString:@"_UISomePrivateLabelSubclass"]) {
        [subview setColor:...
        //do interesting stuff here
    }
}
这是一种非常脆弱的处理方式,但从技术上讲,它从来没有调用过私有API,也不会吓到苹果。在iOS 5中,我曾经做过这样的事情,使iPad上的UIAlertView更大,以便在没有嵌入式滚动视图的情况下拥有更多文本

很多尝试和错误可能是必要的,它可能看起来不漂亮,但它会起作用


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

我的应用程序也需要类似的代码,但最终还是走了很长一段路。很遗憾,没有更简单的方法切换到UIDatePicker的白色文本版本

下面的代码使用UILabel上的类别,在向标签发送setTextColor:消息时,强制标签的文本颜色为白色。为了避免对应用程序中的每个标签都这样做,我对其进行了筛选,使其仅在它是UIDatePicker类的子视图时才适用。最后,一些标签在添加到SuperView之前设置了颜色。要捕获这些,代码将重写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
#导入“UILabel+WhiteUIDatePickerLabels.h”
#进口
@实现UILabel(WhiteUIDatePickerLabel)
+(空)荷载{
静态调度一次;
一次发送(一次发送)^{
[自swizzleInstanceSelector:@选择器(setTextColor:)
withNewSelector:@selector(swizzledSetTextColor:)];
[self swizzleInstanceSelector:@selector(willMoveToSuperview:)
withNewSelector:@selector(swizzledWillMoveToSuperview:)];
});
}
//强制标签的文本颜色仅适用于UIDatePicker及其组件为白色
-(无效)swizzledSetTextColor:(UIColor*)文本颜色{
if([self-view:self-hasSuperviewOfClass:[UIDatePicker类]]||
[self-view:self-hasSuperviewOfClass:NSClassFromString(@“UIDatePickerWeekMonthDayView”)]||
[self-view:self-hasSuperviewOfClass:NSClassFromString(@“UIDatePickerContentView”)]{
[self-SwizzedSetTextColor:[UIColor whiteColor]];
}否则{
//继续默认
[self-SwizzedSetTextColor:textColor];
}
}
//有些UILabel还没有添加到superview中,所以请注意它们何时添加。
-(无效)swizzledWillMoveToSuperview:(UIView*)newSuperview{
[self-SwizzedSettextColor:self.textColor];
[自旋转willmovetosuperview:newSuperview];
}
//--助手--
-(BOOL)视图:(UIView*)视图具有类的超级视图:(类)类{
if(view.superview){
if([view.superview是类的kindof:class]){
返回true;
}
return[self-view:view.superview hasSuperviewOfClass:class];
}
返回false;
}
+(无效)swizzleInstanceSelector:(SEL)原始Selector
withNewSelector:(SEL)newSelector
{
方法originalMethod=class_getInstanceMethod(self,originalSelector);
方法newMethod=class_getInstanceMethod(self,newSelector);
BOOL methodAdded=class\u addMethod([self class],
原选举人,
方法_getImplementation(newMethod),
方法_getTypeEncoding(newMethod));
如果(已添加){
类替换方法([自类],
新闻选民,
方法_getImplementation(原始方法),
方法_getTypeEncoding(原始方法));
}否则{
方法交换实施(原始方法,新方法);
}
}
@结束

这里有一个很好的工作片段。在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]
来显示当前日期

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

这对我很有效。

我发现了一个技巧,可以将字体颜色设置为任何颜色,也不会弄乱今天的标签

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