iOS问题:UITextField的inputAccessoryView旋转后未更新
解决UITextField InputAccessoryView旋转时重绘失效的问题
我看了你的代码,问题主要出在每次旋转时都重新创建button和container控件,而且用frame布局在旋转时容易出现布局错位,另外键盘显示时直接替换inputAccessoryView不会自动刷新。下面是具体的修复方案:
问题根源分析
- 重复创建控件:每次调用
redraw()都会新建button和buttonContainer,不仅浪费内存,还会导致旧的控件引用被丢弃,键盘无法感知新的布局变化。 - Frame布局不可靠:手动计算frame在屏幕旋转时,尺寸计算容易滞后,而且无法自动适配不同设备的屏幕尺寸。
- 未通知键盘更新:当textField处于编辑状态(键盘已弹出)时,直接修改inputAccessoryView的布局,键盘不会自动刷新这个视图的布局。
修复后的代码实现
第一步:重构CustomTextField,使用AutoLayout复用控件
class CustomTextField: UITextField { // 直接初始化控件,避免重复创建 private let button = UIButton() private let buttonContainer = UIView() required init?(coder aDecoder: NSCoder) { super.init(coder: aDecoder) setupInitialViews() } override init(frame: CGRect) { super.init(frame: frame) setupInitialViews() } private func setupInitialViews() { // 配置按钮样式 button.setTitle("BUTTON TEST", for: .normal) button.backgroundColor = .red // 设置container作为inputAccessoryView buttonContainer.backgroundColor = .clear inputAccessoryView = buttonContainer // 添加按钮到container并启用AutoLayout buttonContainer.addSubview(button) button.translatesAutoresizingMaskIntoConstraints = false // 设置按钮的左右上下约束(固定边距) NSLayoutConstraint.activate([ button.leadingAnchor.constraint(equalTo: buttonContainer.leadingAnchor, constant: 24), button.trailingAnchor.constraint(equalTo: buttonContainer.trailingAnchor, constant: -24), button.topAnchor.constraint(equalTo: buttonContainer.topAnchor, constant: 5), button.bottomAnchor.constraint(equalTo: buttonContainer.bottomAnchor, constant: -5) ]) // 初始化按钮高度 updateButtonHeight() } private func updateButtonHeight() { // 根据屏幕横竖屏判断高度,这里可以根据需求调整数值 let isPortrait = UIScreen.main.bounds.width < UIScreen.main.bounds.height let targetHeight: CGFloat = isPortrait ? 56 : 44 // 移除旧的高度约束(如果存在) button.constraints.first(where: { $0.firstAttribute == .height })?.isActive = false // 添加新的高度约束 button.heightAnchor.constraint(equalToConstant: targetHeight).isActive = true // 立即更新布局 buttonContainer.layoutIfNeeded() } func refreshForRotation() { updateButtonHeight() // 如果当前正处于编辑状态,重新唤起键盘以刷新inputAccessoryView guard isFirstResponder else { return } resignFirstResponder() becomeFirstResponder() } }
第二步:修改控制器的旋转处理逻辑
class CustomViewController: UIViewController { @IBOutlet weak var textField: CustomTextField! override func viewWillTransition(to size: CGSize, with coordinator: UIViewControllerTransitionCoordinator) { super.viewWillTransition(to: size, with: coordinator) // 在旋转动画过程中同步更新布局 coordinator.animate(alongsideTransition: { _ in self.textField.refreshForRotation() }, completion: nil) } }
修复说明
- 控件复用:不再每次旋转都创建新的按钮和容器,保持控件的状态一致性,减少内存消耗。
- AutoLayout适配:用自动布局代替手动计算frame,系统会自动处理屏幕旋转时的尺寸变化,布局更稳定。
- 键盘刷新机制:当textField正在编辑时,通过
resignFirstResponder()+becomeFirstResponder()让键盘重新加载inputAccessoryView,确保布局更新立即生效。 - 简化高度计算:直接根据横竖屏设置直观的高度值,也可以根据屏幕宽度比例动态计算,比如
targetHeight = size.width * 0.15,适配不同设备。
内容的提问来源于stack exchange,提问作者Rob
相关产品推荐
相关产品推荐

