實現 `UITextFieldDelegate` 的 `textFieldShouldReturn:` 方法,調用 `[textField resignFirstResponder]` 但鍵盤不收起。
| 原因 | 檢查方法 | 解決 |
|---|---|---|
| Delegate 未設置 | 斷點確認 `textField.delegate == self` | `textField.delegate = self;` 在 `viewDidLoad` 或 XIB/Storyboard 綁定 |
| 返回鍵類型非 Default | 屬性檢查器 `Return Key` 非 `Default` (如 `Next`, `Search`) | 設置為 `Default` 或在代碼中 `textField.returnKeyType = UIReturnKeyDefault;` |
| 文本框非 First Responder | 調用時 `textField.isFirstResponder == NO` | 確保在編輯狀態下調用,或先 `[textField becomeFirstResponder]` |
| 父視圖攔截觸摸 | 父視圖有 `UITapGestureRecognizer` 且 `cancelsTouchesInView = YES` | 設置 `cancelsTouchesInView = NO` 或在手勢中調用 `view.endEditing(true)` |
| 輸入視圖被自定義 InputView 替換 | `textField.inputView != nil` | 自定義輸入視圖需自行實現收起邏輯 |
| 文本框被移除/隱藏 | `textField.superview == nil` 或 `hidden = YES` | 收起鍵盤前確保視圖層級正常 |
當Delegate方法不可靠或場景複雜 (多文本框、嵌套視圖控制器) 時,使用 `UIApplication` 全局收起:
// Objective-C
[[[UIApplication sharedApplication] keyWindow] endEditing:YES];
// Swift
UIApplication.shared.keyWindow?.endEditing(true)
// 或 iOS 15+ 推薦
view.window?.endEditing(true) // 當前視圖層級窗口
// 基類 UIViewController 分類
@implementation UIViewController (KeyboardDismiss)
- (void)addTapToDismissKeyboard {
UITapGestureRecognizer *tap = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(dismissKeyboard)];
tap.cancelsTouchesInView = NO; // 不攔截其他控件點擊
[self.view addGestureRecognizer:tap];
}
- (void)dismissKeyboard {
[self.view endEditing:YES]; // 推薦:視圖層級收起,比 keyWindow 範圍更精確
}
@end
// 使用
- (void)viewDidLoad {
[super viewDidLoad];
[self addTapToDismissKeyboard];
}
extension UIViewController {
func addTapToDismissKeyboard() {
let tap = UITapGestureRecognizer(target: self, action: #selector(dismissKeyboard))
tap.cancelsTouchesInView = false
view.addGestureRecognizer(tap)
}
@objc func dismissKeyboard() {
view.endEditing(true)
}
}