web-dev-qa-db-ja.com

iOS7のUIDatePickerのテキストの色をカスタマイズします(メールボックスと同じように)

私は最もイライラするジレンマを抱えています。私は上下に調査し、AppleはiOS 7を改ざんすることを望まないことをはっきりと見ることができます。改ざんしたいのです。それと承認されます。

私が達成しようとしている主なことは、ラベルの色を白に変更することです。

Mailbox UIDatePicker

私が最初に考えたのは、UIDatePickerを模倣するだけのカスタムUIPickerViewを使用しているということでしたが、そうではないと思います。

小さな断片を拡大してみると、通常のUIDatePicker(黒い線)の残りと、文字 "W"のクリッピングが見つかりました。

Mailbox UIDatePicker fragments

今、私は高低を精練しました。ランタイムハッキングをいくつか行い、UIAppearanceを台無しにし、それが可能かどうかを確認するためにプライベートAPIを掘り下げました。

私は近づき、非常に近くなりましたが、プライベートAPIを使用し、十分に速くスクロールするとラベルが再び黒くなります。

A)ルールを破ったり、b)UIDatePickerを再実装するために数え切れないほどの時間を費やしたりせずに、これを行う方法について完全に迷っています。

メールボックス、あなたの秘密を教えてください!そして、他の誰かが何か提案を持っているなら(そして、私が意味する)、私に知らせてください。

また、これは私が得た最も近いものです:

So close yet so far

36
rnystrom

私は自分のアプリにも同様のものが必要で、長い道のりを歩んでしまいました。 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
59
Sig

これが適切に機能するスニペットです。 iOS 7.18.および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]を使用して現在の日付を表示するためです。

30
arturgrigor

フォントの色を任意の色に設定し、Todayラベルを台無しにしないトリックを見つけました。

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

結果は次のとおりです。

そして、このソリューションのすべてのクレジットは、他のスレッドのこの投稿に行きます: https://stackoverflow.com/a/33459744/1236334

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

これは私のために働いた。

10
fnc12

これを確実に行う方法は、探しているクラス(この場合は、ある種の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を大きくして、埋め込みスクロールビューなしでより多くのテキストを表示するために、このようなことをしていました。

多くの試行錯誤が必要な場合があり、見栄えが悪いかもしれませんが、動作します。

(私が知っている非常に賢い人として、「雨の涙のように、すべてのコードがコンパイラーに失われます。」)

3
Swizzlr