32

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

Marcus Rossel
  • 3,196
  • 1
  • 26
  • 41
Fenda
  • 1,385
  • 3
  • 14
  • 24

16 Answers16

34

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
Dylan Reich
  • 1,400
  • 2
  • 11
  • 14
20

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

Sangram Shivankar
  • 3,535
  • 3
  • 26
  • 38
Pravin Kamble
  • 849
  • 8
  • 12
  • @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`. – Evan R Sep 04 '20 at 01:57
9

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
Aliunco
  • 399
  • 2
  • 9
  • 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` – sudoExclaimationExclaimation May 11 '19 at 09:15
  • Thanks for actually answering the question asked. Thank you – Anthony Dec 22 '19 at 10:40
  • not able to call this method... How to use this? – karthikeyan Jan 30 '21 at 12:57
  • Bravo!!! Superb! Yes, the solution is rather dirty, but Apple's framework is dirty itself - obviously each client would with to customize picker style and look – iago849 Jul 28 '22 at 09:52
6

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()
yildirimosman
  • 133
  • 2
  • 5
6

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()
ObjectiveTC
  • 2,477
  • 30
  • 22
  • 1. Doesn't work anymore 2. Never rely on subviews structure, it's always changing from iOS to iOS – iago849 Jul 28 '22 at 09:57
  • @iago849 I agree this solution was hacky, but iirc this technique was covered by Apple's own WWDC videos and since the Apple API doesn't allow this level of customization, it was necessary to access the subviews as shown in the old WWDC. If you find another better approach for modern iOS, please let me know. – ObjectiveTC Sep 06 '22 at 10:57
4

try this:

    /* set color for UIDatePicker font */

    //text color of today string
    self.datePicker.performSelector("setHighlightsToday:", withObject:Constants.Colors.mainHeaderColor)

    //text color for hoglighted color
    self.datePicker.performSelector("_setHighlightColor:", withObject:Constants.Colors.mainHeaderColor)

    //other text color
    self.datePicker.setValue(Constants.Colors.mainHeaderColor, forKey: "textColor")
4

Adding textColor and highlightsToday to user defined variables did the trick for me :

IB screenshot

CedricSoubrie
  • 6,657
  • 2
  • 39
  • 44
4

Swift 4

override func layoutSubviews() {
    super.layoutSubviews()

    datePickerView.setValue(UIColor.white, forKeyPath: "textColor")
}
IvanPavliuk
  • 1,460
  • 1
  • 21
  • 16
3

The API does not provide a way to do this. You can make a pretty convincing replica yourself using a UIPickerView rather than using UIDatePicker. Se here

Community
  • 1
  • 1
David Karlsson
  • 9,396
  • 9
  • 58
  • 103
  • 2
    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. – Supertecnoboff May 31 '18 at 15:34
3

You can set value using forKeyPath: "textColor". The code:

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

where datePicker is your UIDatePicker object, and the first parameter is the color that you want

lborgav
  • 2,371
  • 19
  • 28
3

I wanted to do this but set it for when someone has the date set prior to now, or after now. I had to reload the data, but when I did it ended up setting it to the current DateTime when using the above example.

So what I did was set a temporary value and then set it after the reload. It does make it do an animated effect, but it works. If you know a better way, let me know...

func dateChanged(sender: UIDatePicker) {
    print(sender.date.description)

    let tempDate = sender.date
    let currentDate = NSDate()

    if originalDate.isLessThanDate(currentDate) {
        originalDate = sender.date
        if sender.date.isGreaterThanDate(currentDate) {
            sender.setValue(UIColor.blackColor(), forKeyPath: "textColor")
            sender.datePickerMode = .CountDownTimer
            sender.datePickerMode = .DateAndTime
            sender.date = tempDate
            sender.reloadInputViews()
        }
    }

    if sender.date.isLessThanDate(currentDate) {
        sender.setValue(UIColor.redColor(), forKeyPath: "textColor")
        sender.datePickerMode = .CountDownTimer
        sender.datePickerMode = .DateAndTime
        sender.date = tempDate
        sender.reloadInputViews()
    }
}
Alsop
  • 53
  • 6
  • I should note that I am using the compare extensions found here: http://stackoverflow.com/questions/26198526/nsdate-comparison-using-swift – Alsop May 18 '16 at 02:27
3

You can use extensions to get and set textColor like bellow

extension UIDatePicker {

    var textColor: UIColor? {
        set {
            setValue(newValue, forKeyPath: "textColor")
        }
        get {
            return value(forKeyPath: "textColor") as? UIColor
        }
    }

}

And then set the color:

datePicker.textColor = .red
Omar Albeik
  • 1,332
  • 13
  • 17
1

I saw the issue you were having and was having a similar issue. Using Xcode 6.3.1 I used this code in mine and worked great:

myPicker.backgroundColor = UIColor.whiteColor()

In case this helps.

Paresh Mayani
  • 127,700
  • 71
  • 241
  • 295
ChallengerGuy
  • 2,385
  • 6
  • 27
  • 43
  • 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. – Michael Feb 24 '16 at 16:25
  • 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 – Markinson Dec 12 '16 at 03:53
1

This worked for me:

setting text color for all date picker subviews

for view in datePicker.subviews {
    view.setValue(UIColor.white, forKeyPath: "textColor")
}
Wojtek Dmyszewicz
  • 4,188
  • 5
  • 30
  • 42
0

I ran into a similar issue with the latest SwiftUI / Swift 5 on XCode 11. All of the options above did not work and the DatePicker either stayed black text or crashed.

In your SwiftUI file set init() before var body

init() {
    UIDatePicker.appearance().backgroundColor = .clear
}

Then in your var body view do this

DatePicker(selection: $dob, in: ...Date(), displayedComponents: .date) {
   Text("Select Date")
}.colorInvert()

That inverted the black text to be white using the iOS Dark Theme. Looks/works great. Hope this helps.

0

In Xcode 11.5, iOS 13, mode is set automatically, by setting the date picker colors in your storyboard as follows:

background: systemBackgroundColor text: labelColor

This results in the following:

enter image description here enter image description here

I found that I also had to set the interface style in the simulator settings:

enter image description here

ICL1901
  • 7,632
  • 14
  • 90
  • 138