UITextField.rightView中的UIControl无法响应controlEvents事件求助
问题原因与解决方案
问题原因
- UITextField的rightView交互限制:当把普通UIView作为UITextField的rightView时,系统会默认限制其内部子视图的事件传递,导致子UIControl无法接收到触摸事件;而UIButton作为UIControl子类,直接作为rightView时会被UITextField特殊处理交互逻辑,因此能正常响应。
- 重复修改视图层次:你在
viewDidLayoutSubviews中每次都会创建新的searchView并重新设置为rightView,频繁变更视图层次会干扰触摸事件的正常传递路径。
解决方案
- 开启容器视图交互:显式设置作为rightView的UIView的
isUserInteractionEnabled = true,确保触摸事件能传递到子UIControl。 - 固定视图创建逻辑:将容器视图创建、添加UIControl、设置rightView的代码移到
viewDidLoad中,只执行一次,保证视图层次稳定。 - 可选:显式开启UIControl交互:虽然UIControl默认已开启交互,显式设置可避免系统意外修改。
修改后的代码
import UIKit class DemoControl: UIControl { } class ViewController: UIViewController { override func viewDidLoad() { super.viewDidLoad() view.addSubview(searchBar) // 视图创建逻辑移到viewDidLoad,仅执行一次 let searchView = UIView(frame: CGRect(x: 0, y: 0, width: demoControl.frame.width, height: demoControl.frame.height)) searchView.isUserInteractionEnabled = true searchView.addSubview(demoControl) searchBar.searchTextField.rightViewMode = .always searchBar.searchTextField.rightView = searchView } override func viewDidLayoutSubviews() { super.viewDidLayoutSubviews() // 仅处理布局自适应,不再重复设置rightView } private lazy var searchBar: UISearchBar = { let view = UISearchBar(frame: CGRect(x: 0, y: 100, width: UIScreen.main.bounds.width - 24, height: 36)) return view }() private lazy var demoControl: DemoControl = { let control = DemoControl(frame: CGRect(x: 0, y: 0, width: 52, height: 24)) control.layer.cornerRadius = 12 control.backgroundColor = .red control.isUserInteractionEnabled = true control.addTarget(self, action: #selector(controlAction), for: .touchUpInside) return control }() private lazy var demoButton: UIButton = { let control = UIButton(frame: CGRect(x: 0, y: 0, width: 52, height: 24)) control.layer.cornerRadius = 12 control.backgroundColor = .red control.addTarget(self, action: #selector(controlAction), for: .touchUpInside) return control }() @objc private func controlAction() { print("Click!!!") } }
内容的提问来源于stack exchange,提问作者Allen
相关产品推荐
相关产品推荐

