如何在UITextField添加leftView后仍居中对齐文本(含占位符)
解决UITextField添加leftView后文本(含占位符)水平居中的优雅方案
我之前也碰到过这个问题,用透明rightView凑数的方式确实不够优雅,其实UIKit本身就提供了更贴合框架设计思路的解决方案——通过自定义UITextField子类,重写文本和占位符的布局方法,就能完美实现需求:文本(包括占位符)水平居中,且输入时不会覆盖leftView。
核心思路
UITextField的文本、编辑状态文本、占位符的绘制区域,分别由textRect(forBounds:)、editingRect(forBounds:)、placeholderRect(forBounds:)这三个方法控制。我们可以重写这些方法,让文本的可用区域自动减去leftView的总占用宽度(包括内边距),同时让这个可用区域保持水平居中。
代码实现
创建一个自定义的UITextField子类:
class CenteredTextFieldWithLeftView: UITextField { // 控制普通状态下文本的绘制区域 override func textRect(forBounds bounds: CGRect) -> CGRect { return adjustedTextRect(forBounds: bounds) } // 控制编辑状态下文本的绘制区域 override func editingRect(forBounds bounds: CGRect) -> CGRect { return adjustedTextRect(forBounds: bounds) } // 控制占位符的绘制区域 override func placeholderRect(forBounds bounds: CGRect) -> CGRect { return adjustedTextRect(forBounds: bounds) } // 统一计算调整后的文本区域 private func adjustedTextRect(forBounds bounds: CGRect) -> CGRect { // 如果没有leftView,直接返回默认布局 guard let leftView = leftView, leftView.bounds.width > 0 else { return super.textRect(forBounds: bounds) } // 计算leftView的总占用宽度(包括leftViewInsets的左右间距) let leftTotalSpace = leftViewInsets.left + leftView.bounds.width + leftViewInsets.right // 文本可用宽度 = TextField总宽度 - leftView总占用宽度 let availableTextWidth = bounds.width - leftTotalSpace // 让文本区域的中心与TextField的中心对齐 let textOriginX = bounds.midX - availableTextWidth / 2 // 返回调整后的文本区域 return CGRect( x: textOriginX, y: bounds.minY, width: availableTextWidth, height: bounds.height ) } }
使用示例
接下来就可以像使用普通UITextField一样使用这个子类,设置leftView和相关属性即可:
// 创建自定义TextField实例 let centeredTextField = CenteredTextFieldWithLeftView(frame: CGRect(x: 40, y: 150, width: 335, height: 48)) centeredTextField.borderStyle = .roundedRect // 设置leftView(比如一个图标) let userIcon = UIImageView(image: UIImage(systemName: "person.fill")) userIcon.contentMode = .scaleAspectFit userIcon.frame = CGRect(x: 0, y: 0, width: 24, height: 24) centeredTextField.leftView = userIcon centeredTextField.leftViewMode = .always // 可选:调整leftView的内边距,让图标和文本之间更美观 centeredTextField.leftViewInsets = UIEdgeInsets(top: 0, left: 12, bottom: 0, right: 8) // 设置占位符和其他属性 centeredTextField.placeholder = "请输入用户名" centeredTextField.textColor = .darkText view.addSubview(centeredTextField)
方案优势
- 优雅自然:完全遵循UIKit的控件布局逻辑,没有多余的冗余视图(比如透明rightView)
- 自适应:如果leftView的宽度或内边距发生变化,文本区域会自动调整,无需额外维护
- 全面覆盖:同时处理了普通文本、编辑状态文本、占位符的居中需求,输入时绝对不会覆盖leftView
内容的提问来源于stack exchange,提问作者j3141592653589793238
相关产品推荐
相关产品推荐

