swift 给 UITextField 设置attributedPlaceholder,同时设置了insertTextPlaceholder将光标和输入位置做了更改,发现当设置 insertTextPlaceholder属性之后,设置的attributedPlaceholder效果失效。
if #available(iOS 13.0, *) {
userNameextField.insertTextPlaceholder(with: CGSize(width: 20, height: 0))
} else {
// Fallback on earlier versions
}
userNameextField.attributedPlaceholder = NSAttributedString(string: "User Name", attributes: [NSAttributedString.Key.font: UIFont.systemFont(ofSize: 12.0), NSAttributedString.Key.foregroundColor: UIColor.red])
这是一个系统bug?
后来放弃使用 insertTextPlaceholder 的方式,重写 placeholderRect(forBounds bounds: CGRect) -> CGRect
的方式也可以实现效果。
以一个简单的登录页面为例
-
重写
placeholderRect(forBounds bounds: CGRect) -> CGRect
方法,设置placeholder的位置,同时也设置了它的字体颜色等属性 -
重写
editingRect(forBounds bounds: CGRect) -> CGRect
方法,设置光标输入位置
class LoginTextField: UITextField {
override init(frame: CGRect) {
super .init(frame: frame)
self.font = UIFont.systemFont(ofSize: 14.0)
self.layer.cornerRadius = 5
self.layer.borderWidth = 0.25
self.layer.borderColor = UIColor.lightGray.cgColor
self.backgroundColor = .white
self.textColor = .black
}
required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
// 重写 `editingRect(forBounds bounds: CGRect) -> CGRect` 方法,设置光标输入位置
override func editingRect(forBounds bounds: CGRect) -> CGRect {
if let view = self.leftView {
return CGRect(x: view.frame.maxX + 8, y: bounds.minY, width: bounds.width, height: bounds.height)
}
return CGRect(x: bounds.minX + 16, y: bounds.minY, width: bounds.width - 16, height: bounds.height)
}
// 重写此方法的目的是为了,当光标从textField移开后,让输入后的内容从我们想要的位置显示,否则输入内容会”跳“到最左侧。
override func textRect(forBounds bounds: CGRect) -> CGRect {
return editingRect(forBounds: bounds)
}
// 重写 `placeholderRect(forBounds bounds: CGRect) -> CGRect` 方法,设置placeholder的位置,同时也设置了它的字体颜色等属性
override func placeholderRect(forBounds bounds: CGRect) -> CGRect {
if let pl = self.placeholder {
self.attributedPlaceholder = NSAttributedString(string: pl, attributes: [NSAttributedString.Key.font: UIFont.systemFont(ofSize: 12.0), NSAttributedString.Key.foregroundColor: UIColor.hexColor(hex: "#d4d3d2")])
}
if let view = self.leftView {
return CGRect(x: view.frame.maxX + 8, y: bounds.minY, width: bounds.width, height: bounds.height)
}
return CGRect(x: bounds.minX + 16, y: bounds.minY, width: bounds.width - 16, height: bounds.height)
}
}
class LogonViewController: BaseViewController {
var encompassIDTextField: LoginTextField!
var userNameTextField: LoginTextField!
var passworldTextField: LoginTextField!
var loginButton: UIButton!
override func viewDidLoad() {
super .viewDidLoad()
self.title = "Log in"
encompassIDTextField = LoginTextField()
encompassIDTextField.placeholder = "Server ID"
view.addSubview(encompassIDTextField)
userNameTextField = LoginTextField()
userNameTextField.placeholder = "User Name"
view.addSubview(userNameTextField)
passworldTextField = LoginTextField()
passworldTextField.placeholder = "Password"
passworldTextField.isSecureTextEntry = true
view.addSubview(passworldTextField)
loginButton = UIButton(type: .custom)
loginButton.backgroundColor = UIColor.hexColor(hex: "#1672c1")
loginButton.layer.cornerRadius = 5
loginButton.setTitle("Log in", for: .normal)
loginButton.setTitleColor(.white, for: .normal)
loginButton.addTarget(self, action: #selector(loginButtonClick), for: .touchUpInside)
view.addSubview(loginButton)
userNameTextField.snp.makeConstraints { make in
make.left.equalTo(44)
make.right.equalTo(-44)
make.height.equalTo(44)
make.centerY.equalToSuperview().offset(-27-64)
}
encompassIDTextField.snp.makeConstraints { make in
make.left.equalTo(userNameTextField)
make.right.equalTo(userNameTextField)
make.height.equalTo(userNameTextField)
make.centerY.equalTo(userNameTextField).offset(-54)
}
passworldTextField.snp.makeConstraints { make in
make.left.equalTo(userNameTextField)
make.right.equalTo(userNameTextField)
make.height.equalTo(userNameTextField)
make.centerY.equalTo(userNameTextField).offset(54)
}
loginButton.snp.makeConstraints { make in
make.left.equalTo(passworldTextField)
make.right.equalTo(passworldTextField)
make.height.equalTo(passworldTextField)
make.centerY.equalTo(passworldTextField).offset(54)
}
}
@objc func loginButtonClick(sender: UIButton) {
}
}
最后效果如下:
主要思路是重写以下方法:
override func editingRect(forBounds bounds: CGRect) -> CGRect {
if let view = self.leftView {
return CGRect(x: view.frame.maxX + 8, y: bounds.minY, width: bounds.width, height: bounds.height)
}
return CGRect(x: bounds.minX + 16, y: bounds.minY, width: bounds.width - 16, height: bounds.height)
}
override func textRect(forBounds bounds: CGRect) -> CGRect {
return editingRect(forBounds: bounds)
}
override func placeholderRect(forBounds bounds: CGRect) -> CGRect {
if let pl = self.placeholder {
self.attributedPlaceholder = NSAttributedString(string: pl, attributes: [NSAttributedString.Key.font: UIFont.systemFont(ofSize: 12.0), NSAttributedString.Key.foregroundColor: UIColor.hexColor(hex: "#d4d3d2")])
}
if let view = self.leftView {
return CGRect(x: view.frame.maxX + 8, y: bounds.minY, width: bounds.width, height: bounds.height)
}
return CGRect(x: bounds.minX + 16, y: bounds.minY, width: bounds.width - 16, height: bounds.height)
}