Set text color and font for UIDatePicker in iOS8/Swift

34,169

Solution 1

Changing the date mode to something else seems to force a re-draw with the newly set text color.

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

Solution 2

you just need to set 2 lines of code in viewdidLoad / viewWillAppear accoding where you using DatePicker.

dobDatePicker.setValue(UIColor.whiteColor(), forKeyPath: "textColor")
dobDatePicker.setValue(false, forKey: "highlightsToday")

See the Result like this:

enter image description here

Solution 3

The only way for changing the font of UIDatePickerView (until now) is swizzling:

you can change the font by an extension of UILabel! (this is not recommended but it works!)

import Foundation
import UIKit

public extension UILabel {
    
    @objc func setFontSwizzled(font: UIFont) {
        if self.shouldOverride() {
            self.setFontSwizzled(font: <THE UIFont FOR ALL DATEPICKERS!>)
        } else {
            self.setFontSwizzled(font: font)
        }
    }
    
    private func shouldOverride() -> Bool {
        let classes = ["UIDatePicker", "UIDatePickerWeekMonthDayView", "UIDatePickerContentView"]
        var view = self.superview
        while view != nil {
            let className = NSStringFromClass(type(of: view!))
            if classes.contains(className) {
                return true
            }
            view = view!.superview
        }
        return false
    }
    
    private static let swizzledSetFontImplementation: Void = {
        let instance: UILabel = UILabel()
        let aClass: AnyClass! = object_getClass(instance)
        let originalMethod = class_getInstanceMethod(aClass, #selector(setter: font))
        let swizzledMethod = class_getInstanceMethod(aClass, #selector(setFontSwizzled))
        
        if let originalMethod = originalMethod, let swizzledMethod = swizzledMethod {
            // switch implementation..
            method_exchangeImplementations(originalMethod, swizzledMethod)
        }
    }()
    
    static func swizzleSetFont() {
        _ = self.swizzledSetFontImplementation
    }
}

and for changing the color you just simply call the function below:

datePicker.setValue(UIColor.whiteColor(), forKeyPath: "textColor")

if it's necessary to be re-rendered you need to call:

datePicker.datePickerMode = .CountDownTimer
datePicker.datePickerMode = .DateAndTime //or whatever your original mode was

Solution 4

I believe this is the definitive solution for countdown timers.
It's an expansion of yildirimosman's answer.

//text color
datePicker.setValue(UIColor.whiteColor(), forKey: "textColor")
//picker background
datePicker.subviews[0].subviews[0].backgroundColor = UIColor.clearColor() //the picker's own background view
//dividers
datePicker.subviews[0].subviews[1].backgroundColor = UIColor.whiteColor()
datePicker.subviews[0].subviews[2].backgroundColor = UIColor.whiteColor()
//labels: "hours" and "min"
datePicker.subviews[0].subviews[3].setValue(UIColor.lightGrayColor(), forKey: "textColor")
datePicker.subviews[0].subviews[4].setValue(UIColor.lightGrayColor(), forKey: "textColor")
//refresh the tableview (to force initial row textColor to change to white)
datePicker.subviews[0].setNeedsLayout()
datePicker.subviews[0].layoutIfNeeded()

Solution 5

you can use

datePicker.setValue(UIColor.whiteColor(), forKey: "textColor")
datePicker.setValue(false, forKey: "highlightsToday")
//for selector color
datePickerView.subviews[0].subviews[1].backgroundColor = UIColor.whiteColor()
datePickerView.subviews[0].subviews[2].backgroundColor = UIColor.whiteColor()
Share:
34,169
Fenda
Author by

Fenda

Updated on September 08, 2021

Comments

  • Fenda
    Fenda almost 3 years

    I've been having trouble trying to set the UIDatePicker font and color. Everything else in my app was fairly straightforward to adjust except this. Does anybody know how to do this? I'm using Swift for iOS8.

    screenshot

  • villy393
    villy393 over 8 years
    I can't believe this is something we need to hack with setValue forKeypath. Its not like we are trying to replace the the date values with emoji's or something random.
  • Michael
    Michael over 8 years
    This will change the background color of the picker itself, not the font of color of the font. Personally, I think it would make this guys design look terrible.
  • Klemen
    Klemen over 8 years
    This is the best answer. I try many of them an this one works and dont corrupt Today label in picker.
  • Alsop
    Alsop about 8 years
    I should note that I am using the compare extensions found here: stackoverflow.com/questions/26198526/…
  • ObjectiveTC
    ObjectiveTC almost 8 years
    See my other answer for expanded solution.
  • Markinson
    Markinson over 7 years
    This is what I needed man. But unfortunately your post was so far down here that I had to find it somewhere else. Hopefully more people see it earlier
  • Supertecnoboff
    Supertecnoboff about 6 years
    For anything else a replica would be fine, but for dates?! Surely not - as we know there are so many things that can go wrong when an indie dev tries to mess around with dates on their own - timezone changes, daylight savings, etc.... The UIDatePicker takes care of all that and provides a reliable NSDate object. It's just a shame that it doesn't have some basic customisation options.
  • gohnjanotis
    gohnjanotis almost 6 years
    This approach causes a crash if the UIDatePicker is being used when the mode is switched.
  • sudoExclaimationExclaimation
    sudoExclaimationExclaimation about 5 years
    This is the only solution which worked for font changing! Bravo! Here's the order to call the functions: let datePicker = UIDatePicker() UILabel.swizzleSetFont() datePicker.setValue(themeMacro(themeKey: "titleColor"), forKey: "textColor") datePicker.datePickerMode = .date
  • Anthony
    Anthony over 4 years
    Thanks for actually answering the question asked. Thank you
  • Evan R
    Evan R almost 4 years
    @ScottyBlades You can get access to the main dispatch queue from any function; that's not why this code needs to go there (if indeed it does—I haven't tested it). If the answer is correct, it needs to go there because of the order of UIKit's view lifecycle for UIViewController.
  • karthikeyan
    karthikeyan over 3 years
    not able to call this method... How to use this?