Skip to content

Instantly share code, notes, and snippets.

@ngeri
Created August 30, 2021 17:36
Show Gist options
  • Save ngeri/0080d429a0b6d195eeff3f54dafb0c11 to your computer and use it in GitHub Desktop.
Save ngeri/0080d429a0b6d195eeff3f54dafb0c11 to your computer and use it in GitHub Desktop.
Unexpected default kerning when using attributedText of UITextField
import UIKit
final class ViewController: UIViewController {
private lazy var textField: UITextField = {
let view = UITextField()
view.translatesAutoresizingMaskIntoConstraints = false
view.delegate = self
view.borderStyle = .roundedRect
view.keyboardType = .numberPad
return view
}()
override func viewDidLoad() {
super.viewDidLoad()
title = "Attributed UITextField"
view.backgroundColor = .black
view.addGestureRecognizer(UITapGestureRecognizer(target: self, action: #selector(backgroundTap)))
view.addSubview(textField)
NSLayoutConstraint.activate([
textField.leadingAnchor.constraint(equalTo: view.leadingAnchor, constant: 8),
textField.centerYAnchor.constraint(equalTo: view.centerYAnchor),
textField.trailingAnchor.constraint(equalTo: view.trailingAnchor, constant: -8)
])
}
@objc func backgroundTap() {
textField.resignFirstResponder()
}
}
extension ViewController: UITextFieldDelegate {
func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool {
let cursorLocation = textField.position(from: textField.beginningOfDocument, offset: range.location + string.count)
guard let text = textField.text, let range = Range(range, in: text) else { return false }
let newText = text.replacingCharacters(in: range, with: string)
textField.attributedText = addKerning(to: .init(string: newText))
if let cursorLocation = cursorLocation {
textField.selectedTextRange = textField.textRange(from: cursorLocation, to: cursorLocation)
}
return false
}
// func textFieldShouldReturn(_ textField: UITextField) -> Bool {
// textField.selectedTextRange = nil
// return true
// }
}
extension ViewController {
func addKerning(to string: NSAttributedString) -> NSAttributedString {
let groupSize = 3
let kernSize: CGFloat = 4
guard string.length > groupSize else {
return string
}
let attributedString = NSMutableAttributedString(attributedString: string)
for index in stride(from: string.length - 1 - groupSize, through: 0, by: -groupSize) {
attributedString.addAttribute(.kern, value: kernSize, range: NSRange(location: index, length: 1))
}
return attributedString
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment