Swift 4.0自定义UITextField二次编辑时文本偏移重叠问题求助
解决UITextField二次编辑时文本偏移的问题
我之前也碰到过一模一样的问题!你的自定义TextField之所以会在二次编辑时文本偏移回初始位置,核心原因是没有通过系统提供的方法正确设置文本的内边距,而是依赖draw(_ rect:)里的逻辑,这会导致系统在状态变化时重新计算文本区域出错。
问题分析
你当前的代码只在updateView()里处理了leftView的布局,但文本的实际绘制区域(不管是普通状态还是编辑状态)还是用的系统默认值。当文本框从编辑状态退出再重新进入时,系统会重新调用文本区域计算的方法,这时候没有自定义的偏移逻辑,文本就会回到初始位置。
另外,在draw(_ rect:)里绘制下划线也不是最优解——这个方法会被频繁调用,容易导致布局异常或者重复绘制。
修复方案
我们需要重写系统的文本区域计算方法,同时改用更可靠的方式添加下划线:
- 重写文本区域方法,确保普通状态和编辑状态下文本都有正确的偏移:
override func textRect(forBounds bounds: CGRect) -> CGRect { var textRect = super.textRect(forBounds: bounds) // 如果有左侧图标,调整文本起始位置 if leftViewMode == .always, let leftView = leftView { textRect.origin.x = leftView.frame.maxX + kInset } return textRect } override func editingRect(forBounds bounds: CGRect) -> CGRect { // 编辑状态下使用和普通状态一样的文本区域,避免偏移 return textRect(forBounds: bounds) }
- 改用CALayer绘制下划线,把原来
draw(_ rect:)里的下划线逻辑移到layoutSubviews()中,这样布局变化时会自动更新:
override func layoutSubviews() { super.layoutSubviews() // 先移除旧的下划线layer,避免重复添加 layer.sublayers?.filter { $0.name == "textFieldUnderline" }.forEach { $0.removeFromSuperlayer() } guard leftViewMode == .always, let leftView = leftView else { return } let underlineLayer = CALayer() underlineLayer.name = "textFieldUnderline" // 下划线的位置:从leftView的左侧开始,到文本框右边缘,粗细2pt underlineLayer.frame = CGRect( x: leftView.frame.minX, y: bounds.height - 2, width: bounds.width - leftView.frame.minX, height: 2 ) underlineLayer.backgroundColor = Colors.ButtonColor.cgColor layer.addSublayer(underlineLayer) }
- 移除旧的draw方法:把原来
draw(_ rect:)里的下划线绘制代码删掉,避免和新的layer逻辑冲突。
为什么这样有效?
textRect(forBounds:)和editingRect(forBounds:)是系统用来确定文本绘制位置的核心方法,重写它们能确保不管文本框处于什么状态,文本的偏移都是一致的。- 用CALayer绘制下划线比在
draw(_ rect:)里绘制更高效,而且能自动跟随文本框的布局变化,不会出现绘制异常。
按照这个修改后,你再测试二次编辑的场景,文本就不会再偏移啦!
内容的提问来源于stack exchange,提问作者Jimmy
相关产品推荐
相关产品推荐

