簡體   English   中英

出現鍵盤時調整屏幕大小

[英]Resize the screen when keyboard appears

我正在構建一個聊天應用程序。 出現鍵盤時,我必須移動文本字段。 我正在使用以下代碼執行此操作:

func keyboardWillShow(notification: NSNotification) {
    if let userInfo = notification.userInfo {
        if let keyboardSize =  (userInfo[UIKeyboardFrameBeginUserInfoKey] as? NSValue)?.CGRectValue() {
            kbHeight = keyboardSize.height
            self.animateTextField(true)
        }
    }
}
func keyboardWillHide(notification: NSNotification) {
    self.animateTextField(false)
}

func animateTextField(up: Bool) {
    var movement = (up ? -kbHeight : kbHeight)

    UIView.animateWithDuration(0.3, animations: {
        self.view.frame = CGRectOffset(self.view.frame, 0, movement)
    })
}

但是當我使用此代碼時,第一條消息不會顯示。 我想我必須調整 tableview 的大小。

以下是鍵盤出現之前之后的屏幕截圖:

我正在使用自動布局。

我該如何解決這個問題?

您可以創建表格視圖底部自動布局約束的出口。

然后只需使用此代碼:

func keyboardWillShow(sender: NSNotification) {
    let info = sender.userInfo!
    var keyboardSize = (info[UIKeyboardFrameEndUserInfoKey] as! NSValue).cgRectValue.height
    bottomConstraint.constant = keyboardSize - bottomLayoutGuide.length

    let duration: TimeInterval = (info[UIKeyboardAnimationDurationUserInfoKey] as! NSNumber).doubleValue

    UIView.animate(withDuration: duration) { self.view.layoutIfNeeded() }
}

func keyboardWillHide(sender: NSNotification) {
    let info = sender.userInfo!
    let duration: TimeInterval = (info[UIKeyboardAnimationDurationUserInfoKey] as! NSNumber).doubleValue
    bottomConstraint.constant = 0

    UIView.animate(withDuration: duration) { self.view.layoutIfNeeded() }
}

如果您在創建底部約束時遇到問題:

在故事板中

  • 選擇您的搜索欄。
  • 在右下角,您會看到 3 個圖標。 單擊中間的看起來像|-[]-| .
  • 在該彈出窗口的頂部,有 4 個框。 在底部輸入 0。
  • 約束已創建!

現在您可以將它拖到您的視圖控制器並將其添加為插座。

另一種解決方案是設置tableView.contentInset.bottom 但我以前沒有這樣做過。 如果你願意,我可以試着解釋一下。

使用插圖:

func keyboardWillShow(sender: NSNotification) {
    let info = sender.userInfo!
    let keyboardSize = (info[UIKeyboardFrameEndUserInfoKey] as! NSValue).cgRectValue.height

    tableView.contentInset.bottom = keyboardSize
}

func keyboardWillHide(sender: NSNotification) {
    tableView.contentInset.bottom = 0
}

您可以嘗試使用此代碼來設置插圖。 我自己還沒有嘗試過,但應該是這樣的。

編輯:根據 nacho4d 的建議更改了持續時間

2020 更新

正確使用約束...

在 iOS 中只有一種方法可以正確處理這個爛攤子。

  1. KUIViewController下面的KUIViewController粘貼到您的項目中,

  2. 創建一個對“內容底部”非常簡單的約束。

  3. 將該約束bottomConstraintForKeyboard

KUIV​​iewController 將始終自動正確地調整內容視圖的大小

絕對一切都是完全自動的

所有 Apple 行為都以標准方式正確處理,例如通過點擊關閉等。

你已經 100% 完成了。

那么“你應該調整哪個視圖的大小?”

不能使用.view ...

因為......你不能在 iOS 中調整.view大小!!!!!! 哦!

只需制作一個名為“holder”的 UIView。 它位於.view

把你的所有東西都放在“持有人”里。

Holder 當然會有四個簡單的約束 top/bottom/left/right 到.view

“持有人”的底部約束確實是bottomConstraintForKeyboard

你完成了。

給客戶寄一張賬單然后去喝酒。

沒有什么可做的了。

class KUIViewController: UIViewController {

    // KBaseVC is the KEYBOARD variant BaseVC. more on this later

    @IBOutlet var bottomConstraintForKeyboard: NSLayoutConstraint!

    @objc func keyboardWillShow(sender: NSNotification) {
        let i = sender.userInfo!
        let s: TimeInterval = (i[UIResponder.keyboardAnimationDurationUserInfoKey] as! NSNumber).doubleValue
        let k = (i[UIResponder.keyboardFrameEndUserInfoKey] as! NSValue).cgRectValue.height
        bottomConstraintForKeyboard.constant = k
        // Note. that is the correct, actual value. Some prefer to use:
        // bottomConstraintForKeyboard.constant = k - bottomLayoutGuide.length
        UIView.animate(withDuration: s) { self.view.layoutIfNeeded() }
    }

    @objc func keyboardWillHide(sender: NSNotification) {
        let info = sender.userInfo!
        let s: TimeInterval = (info[UIResponder.keyboardAnimationDurationUserInfoKey] as! NSNumber).doubleValue
        bottomConstraintForKeyboard.constant = 0
        UIView.animate(withDuration: s) { self.view.layoutIfNeeded() }
    }

    @objc func clearKeyboard() {
        view.endEditing(true)
        // (subtle iOS bug/problem in obscure cases: see note below
        // you may prefer to add a short delay here)
    }

    func keyboardNotifications() {
        NotificationCenter.default.addObserver(self,
            selector: #selector(keyboardWillShow),
            name: UIResponder.keyboardWillShowNotification,
            object: nil)
        NotificationCenter.default.addObserver(self,
            selector: #selector(keyboardWillHide),
            name: UIResponder.keyboardWillHideNotification,
            object: nil)
    }

    override func viewDidLoad() {
        super.viewDidLoad()
        keyboardNotifications()
        let t = UITapGestureRecognizer(target: self, action: #selector(clearKeyboard))
        view.addGestureRecognizer(t)
        t.cancelsTouchesInView = false
    }
}

簡單地 ...

在鍵盤可能出現的任何地方使用 KUIViewController。

class AddCustomer: KUIViewController, SomeProtocol {

class EnterPost: KUIViewController {

class EditPurchase: KUIViewController {

在那些屏幕上,現在關於鍵盤的一切都是完全自動的。

你完成了。

呼。


*小腳注 - 背景點擊正確關閉鍵盤。 這包括落在您內容上的點擊次數。 這是正確的 Apple 行為 任何不尋常的變化都需要大量非常反蘋果的定制編程。

*非常小的腳注 - 因此,屏幕上的任何和所有按鈕每次都可以 100% 正確工作。 然而,在嵌套 (!) 滾動視圖中嵌套 (!) 容器視圖和嵌套 (!) 頁面視圖容器 (!!!!) 的令人難以置信的模糊情況下,您可能會發現按鈕似乎不起作用。 這似乎是當前 iOS 中的一個(晦澀的!)問題。 如果您遇到這個令人難以置信的晦澀問題,幸運的是解決方案很簡單。 查看函數clearKeyboard() ,只需添加一個短暫的延遲,就完成了。

@objc func clearKeyboard() {
    DispatchQueue.main.asyncAfter(deadline: .now() + .milliseconds(100)) {
        self.view.endEditing(true)
    }
}

(來自用戶@wildcat12 https://stackoverflow.com/a/57698468/294884 的一個很好的提示)

來自@Fattie 的消息:

細節 -(不幸的是)點擊您的內容也會關閉鍵盤。 (他們都得到了這個事件。)然而,這幾乎總是正確的行為; 試一試。 沒有合理的方法可以避免這種情況,所以忘記它並使用 Apple 流程。

這可以通過實現以下UIGestureRecognizerDelegate的方法來解決:

func gestureRecognizer(_ gestureRecognizer: UIGestureRecognizer, shouldReceive touch: UITouch) -> Bool {
        return !(touch.view?.isKind(of: UIControl.self) ?? true)
    }

這樣,如果用戶觸摸任何UIControl (UIButton、UITextField 等),手勢識別器將不會調用clearKeyboard()方法。

為此,請記住在類定義或擴展中對 UIGestureRecognizerDelegate 進行子類化。 然后,在 viewDidLoad() 中,您應該將手勢識別器委托指定為 self。


准備復制和粘貼代碼:

// 1. Subclass UIGestureRecognizerDelegate
class KUIViewController: UIViewController, UIGestureRecognizerDelegate {

@IBOutlet var bottomConstraintForKeyboard: NSLayoutConstraint!

func keyboardWillShow(sender: NSNotification) {
    let i = sender.userInfo!
    let k = (i[UIKeyboardFrameEndUserInfoKey] as! NSValue).cgRectValue.height
    bottomConstraintForKeyboard.constant = k - bottomLayoutGuide.length
    let s: TimeInterval = (i[UIKeyboardAnimationDurationUserInfoKey] as! NSNumber).doubleValue
    UIView.animate(withDuration: s) { self.view.layoutIfNeeded() }
}

func keyboardWillHide(sender: NSNotification) {
    let info = sender.userInfo!
    let s: TimeInterval = (info[UIKeyboardAnimationDurationUserInfoKey] as! NSNumber).doubleValue
    bottomConstraintForKeyboard.constant = 0
    UIView.animate(withDuration: s) { self.view.layoutIfNeeded() }
}

func keyboardNotifications() {
    NotificationCenter.default.addObserver(self,
        selector: #selector(keyboardWillShow),
        name: Notification.Name.UIKeyboardWillShow,
        object: nil)
    NotificationCenter.default.addObserver(self,
        selector: #selector(keyboardWillHide),
        name: Notification.Name.UIKeyboardWillHide,
        object: nil)
}

func clearKeyboard() {
    view.endEditing(true)
}

override func viewDidLoad() {
    super.viewDidLoad()
    keyboardNotifications()
    let t = UITapGestureRecognizer(target: self, action: #selector(clearKeyboard))
    view.addGestureRecognizer(t)
    t.cancelsTouchesInView = false

    // 2. Set the gesture recognizer's delegate as self
    t.delegate = self
}

// 3. Implement this method from UIGestureRecognizerDelegate
func gestureRecognizer(_ gestureRecognizer: UIGestureRecognizer, shouldReceive touch: UITouch) -> Bool {
    return !(touch.view?.isKind(of: UIControl.self) ?? true)
}
}

如果您不想自己解決這個問題,您可能會發現TPKeyboardAvoiding框架很有用

只需按照“安裝說明”即可,即將適當的 .h/.m 文件拖放到您的項目中,然后讓您 ScrollView/TableView 成為如下子類:

自定義類

也許它會幫助某人。 您可以在不使用界面構建器的情況下實現所需的行為

首先,您需要創建約束並計算安全區域插入,以便正確支持無按鈕設備

var container: UIView!
var bottomConstraint: NSLayoutConstraint!
let safeInsets = UIApplication.shared.windows[0].safeAreaInsets

然后在代碼中的某處初始化它

container = UIView()
bottomConstraint = container.bottomAnchor.constraint(equalTo: view.bottomAnchor)

附加它以查看和激活

view.addSubview(container)

NSLayoutConstraint.activate([
       ...

       container.leadingAnchor.constraint(equalTo: view.leadingAnchor),
       container.trailingAnchor.constraint(equalTo: view.trailingAnchor),
       container.topAnchor.constraint(equalTo: view.topAnchor),
       bottomConstraint,

       ...
 ])

最后

@objc func keyboardWillShow(notification: NSNotification) {
       if let keyboardSize = (notification.userInfo?[UIResponder.keyboardFrameEndUserInfoKey] as? NSValue)?.cgRectValue {

       if bottomConstraint.constant == 0 {
          bottomConstraint.constant = -keyboardSize.height + safeInsets.bottom     
          view.layoutIfNeeded()
       }
    }
}

@objc func keyboardWillHide(notification: NSNotification) {
       bottomConstraint.constant = 0
       view.layoutIfNeeded()
}

此外,如果您的視圖是可滾動的,並且您想用鍵盤將其向上移動並在鍵盤隱藏時返回到初始位置,則可以更改視圖的 contentOffset

view.contentOffset = CGPoint(x: view.contentOffset.x, y: view.contentOffset.y + keyboardSize.height - safeInsets.bottom)

向上滾動,以及

view.contentOffset = CGPoint(x: view.contentOffset.x, y: view.contentOffset.y - keyboardSize.height + safeInsets.bottom)

將其向下移動

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM