Hi I have a textField to provide Date for Birth(Requirement). Initially the textField should have the text "DD MM YYYY" . And if I key in the date of birth, need to remove characters (DD MM YYYY) one by one.
Scenario:
DD MM YYYY is the text displayed in TextField initially.
After typing first digit(for example 3), it should be like " 3D MM YYYY "
After typing second digit(for example 1, it should be like " 31 MM YYYY "
After typing third digit(for example 0, it should be like " 31 0M YYYY "
After typing fourth digit(for example 8, it should be like " 31 08 YYYY " and so on.... Is this possible?
In previous code, there are some issues with darkmode:
- placeholder hardly readable (a known bug in iOS in dark mode)
- when switching mode, colors did not immediately adjust.
Here is the improved code:
class TextFieldDynPlaceHolder: UITextField, UITextFieldDelegate {
let defaultPlaceHolder = "DD MM YYYY" // Could set it as IBInspectable property
var thePlaceHolder : String! // To be set at call
// --------------------- commonInit ----------------------------------------------------
// Description: set the placeholder from text
// Parameters
// Comments:
// Need to set borderStyle (bug in iOS): https://stackoverflow.com/questions/64057501/how-to-fix-uitextfield-background-image-not-displayed-after-ios14
// -------------------------------------------------------------------------------------------------
func commonInit() {
delegate = self
thePlaceHolder = defaultPlaceHolder // "DD MM YYYY"
self.background = image(from: thePlaceHolder)
self.borderStyle = .line
}
override init(frame: CGRect) {
super.init(frame: frame)
commonInit()
}
required init?(coder: NSCoder) {
super.init(coder: coder)
commonInit()
}
// --------------------- traitCollectionDidChange -------------------------------------------
// Description: Adjust colors when switching mode light / dark.
// Parameters
// previousTraitCollection: UITraitCollection?
// Comments:
// -------------------------------------------------------------------------------------------------
override func traitCollectionDidChange(_ previousTraitCollection: UITraitCollection?) {
super.traitCollectionDidChange(previousTraitCollection)
adaptPlaceHolder(self)
}
// --------------------- image -------------------------------------------
// Description: Create image from a text.
// Parameters
// from text: String?
// Comments:
// https://stackoverflow.com/questions/51100121/how-to-generate-an-uiimage-from-custom-text-in-swift
// In fact, placeholderText unreadable in darkMode. https://stackoverflow.com/questions/58478744/uitextfield-placeholder-text-is-unreadable-in-ios13-dark-mode
// -------------------------------------------------------------------------------------------------
func image(from text: String?) -> UIImage? {
let frame = CGRect(x: 0, y: 0, width: self.frame.width, height: self.frame.height)
let nameLabel = UILabel(frame: frame)
nameLabel.textAlignment = .left
nameLabel.backgroundColor = .systemBackground
if traitCollection.userInterfaceStyle == .light {
nameLabel.textColor = .placeholderText // .darkGray if .placeholderText is too light
} else {
nameLabel.textColor = .systemGray
}
nameLabel.font = self.font
nameLabel.text = text
UIGraphicsBeginImageContext(frame.size)
if let currentContext = UIGraphicsGetCurrentContext() {
nameLabel.layer.render(in: currentContext)
let nameImage = UIGraphicsGetImageFromCurrentImageContext()
return nameImage
}
return nil
}
// --------------------- adaptPlaceHolder --------------------------------------
// Description: Trims placeHolder text when first characters typed ; rebuilds image.
// Parameters
// textField: UITextField
// Comments:
// -------------------------------------------------------------------------------------------------
func adaptPlaceHolder(_ textField: UITextField) {
var trimmedPlaceHolder = defaultPlaceHolder
if let typed = textField.text?.count, typed > 0 {
trimmedPlaceHolder = String(defaultPlaceHolder.dropFirst(typed))
// And we replace with spaces
for _ in 0..<typed {
trimmedPlaceHolder = " " + trimmedPlaceHolder
}
self.background = image(from: trimmedPlaceHolder)
} else {
self.background = image(from: trimmedPlaceHolder)
}
}
// --------------------- adaptPlaceHolder --------------------------------------
// Description: redraws placeHolder image when characters typed and checks characters are decimals
// Parameters
// textField: UITextField
// Comments:
// -------------------------------------------------------------------------------------------------
func textFieldDidChangeSelection(_ textField: UITextField) {
if let typedText = textField.text {
for c in typedText.unicodeScalars {
if !CharacterSet.decimalDigits.contains(c) && !CharacterSet.whitespaces.contains(c) {
// And play a beep
textField.text = String(textField.text!.dropLast())
}
}
}
adaptPlaceHolder(textField)
}
// --------------------- textField --------------------------------------
// Description: test the validity of entry (as a Date for instance)
// Parameters
// textField: UITextField
// shouldChangeCharactersIn range: NSRange
// replacementString string: String
// Comments:
// To be implemented
// -------------------------------------------------------------------------------------------------
func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool {
return true
}
}