---
# System prepended metadata

title: textFiled 遮住鍵盤問題解決方案

---

textFiled 遮住鍵盤問題解決方案
===

# 問題
`mainView` 是包含一個 `tableView` 與 `textField`
點擊 `textField` 時鍵盤不要擋住，希望能把 mainview 往上移動到鍵盤的上方

# Method 1
```swift
class ViewController: UIViewController, UITextFieldDelegate {
    @IBOutlet weak var textfield: UITextField!
    @IBOutlet weak var titleView: UIView!
    @IBOutlet weak var mainView: UIView!
    
    override func viewDidLoad() {
        super.viewDidLoad()
        
        textfield.delegate = self
        
        // 增加點擊背景收起鍵盤
        addHideKeyboardWhenTappedAround()
        
        NotificationCenter.default.addObserver(self, selector: #selector(keyboardShown),
                           name: UIResponder.keyboardWillShowNotification,
                           object: nil)
        NotificationCenter.default.addObserver(self, selector: #selector(keyboardHidden),
                           name: UIResponder.keyboardWillHideNotification,
                           object: nil)
        
    }
    
    override func viewWillDisappear(_ animated: Bool) { {
        NotificationCenter.default.removeObserver(self)
    }
    
    private func addHideKeyboardWhenTappedAround() {
        let tapAround: UITapGestureRecognizer =
        UITapGestureRecognizer(target: self,
                               action: #selector(dismissKeyboard))
        // tapAround.cancelsTouchesInView = false
        view.addGestureRecognizer(tapAround)
    }
    
    @objc func dismissKeyboard() {
        view.endEditing(true)
    }
    
    @objc func keyboardShown(notification: Notification) {
        guard let info = notification.userInfo,
              let keyboardFrame = (info[UIResponder.keyboardFrameEndUserInfoKey] as? NSValue)?.cgRectValue else {
            return
        }

        // 鍵盤高度
        let keyboardHeight = keyboardFrame.height

        // textfield 在 self.view 座標系的位置
        let editingTextFieldFrame = textfield.convert(textfield.bounds, to: self.view)

        // textfield 的底部 Y 座標
        let editingTextFieldMaxY = editingTextFieldFrame.maxY

        // 畫面高度 - 鍵盤高度 = 鍵盤上緣
        let keyboardMinY = self.view.frame.height - keyboardHeight

        // textfield 與鍵盤的間距，如果小於 0 代表被擋住
        let overlap = editingTextFieldMaxY - keyboardMinY + 20  // +20 buffer

        if overlap > 0 {
            UIView.animate(withDuration: 0.25) {
                self.mainView.transform = CGAffineTransform(translationX: 0, y: -overlap)
            }
        }
    }
    
    
    @objc func keyboardHidden(notification: Notification) {
        UIView.animate(withDuration: 0.25) {
            self.mainView.transform = .identity
        }
    }
}

```

使用 `transform` 和 `CGRect` 在 iOS UI 裡的差異，核心在於影響的層次不同
| 特性         | `CGRect` (`frame`)             | `transform`               |
| ---------- | ------------------------------ | ------------------------- |
| 作用         | 直接改變 View 的位置與大小               | 在顯示層做仿射變換(Affine Transform），不動原本的 frame 定義 |
| AutoLayout | 容易衝突（因為 frame 被 constraint 控制） | 不影響 constraint，比較安全       |
| 動畫用途       | 一般較少用，需重新 layout               | 非常常用（移動 translation、縮放 scale、旋轉 rotation）            |
| 適合場景       | 需要永久改變 View 的位置/大小             | 暫時調整或動畫效果                 |

```swift=
view.frame = CGRect(x: 0, y: 100, width: 200, height: 50)    // 把 view 移到 y = 100，寬高變 200x50

view.transform = CGAffineTransform(translationX: 0, y: -100) // 向上移動 100
view.transform = CGAffineTransform(scaleX: 1.5, y: 1.5)     // 放大 1.5 倍
view.transform = CGAffineTransform(rotationAngle: .pi/4)    // 旋轉 45 度
```

# Method 2
iOS15+ 新推出的 **UIKeyboardLayout**，可以自動解決鍵盤擋住畫面的問題。
需滿足：
- 確認要移動的 `UIView`，這邊假設是上述的 `mainView`
- 要移動的 `UIView` 的底部必須對齊
    1. `UIView` 的 **Layout Guides** 啟用 **Keyboard** 選項
![截圖 2025-08-29 11.33.13](https://hackmd.io/_uploads/Hkzj1i0Yxg.png)
    2. 在 xib 左側就會出現 **Keyboard Layout guide**，直接將 `mainView` 拖曳到 **Keyboard Layout Guide** 設置對齊它的 top。
![截圖 2025-08-29 11.37.39](https://hackmd.io/_uploads/H1Zslj0Kex.png)

注意：若是要被往上移的 UIView 是子 UIView，則每一層的 super view 都要設置底部對齊 **Keyboard Layout Guide**

```swift=
override func viewDidLoad() {
    super.viewDidLoad()
    
     // mainView 底部 = 鍵盤上緣 - 0（或留個間距 8）
    mainView.bottomAnchor.constraint(equalTo: view.keyboardLayoutGuide.topAnchor, constant: 0).isActive = true
}
```
這樣做效果就是：
- 鍵盤收起時 → keyboardLayoutGuide.topAnchor 會等於 Safe Area Bottom，所以 `mainView` 會貼到底部。
- 鍵盤彈出時 → keyboardLayoutGuide.topAnchor 自動移到鍵盤上緣，`mainView` 會跟著被頂上去。
- 不需要寫 `NotificationCenter` 的監聽，也不用自己算 offset。


###### tags: `textField`
