键盘消失时增加Tableview的高度?

Posted

技术标签:

【中文标题】键盘消失时增加Tableview的高度?【英文标题】:Increase the Height of the Tableview when the Keyboard Disappears? 【发布时间】:2018-05-22 04:26:39 【问题描述】:

我想在键盘消失时增加表格视图的高度。我有一个从底部向上填充的表格视图。 tableview 没有完全填充数据,这意味着 tableview 顶部有一些空白空间。表格视图中会有一些单元格。由于表格视图是从底部向上填充的,因此这些单元格应该朝向表格视图的底部。当显示键盘时,tableview 的总高度大约是屏幕的一半。当键盘消失时,tableview 的总高度应该几乎是整个屏幕。这意味着当键盘消失时,单元格应从屏幕下方开始。

这是tableview中有两个单元格时的样子:

这是向 tableview 添加另外两个单元格时的样子:

这是键盘消失后的样子:

当键盘消失时,四个单元格应该从屏幕底部开始,而不是从屏幕中间开始。四个单元格应该向下移动,以便它们从屏幕底部的灰线开始。第一个单元格(显示“Apple”)的位置与屏幕底部的灰线位置之间不应有很大的差距。同时,tableView 本身应该更大。这意味着虽然 tableview 的顶部保持在同一个位置,但 tableview 的底部现在比以前低了,因为键盘现在没有占据大约一半的屏幕。我怎样才能做到这一点?谢谢。

这是我现在的代码:

class ViewController: UIViewController, UITableViewDataSource, UITableViewDelegate 

    @IBOutlet weak var textField: UITextField!
    @IBOutlet weak var lowerGrayLine: UIView!

    @IBOutlet weak var tableView: UITableView!

    var fruits = [FruitModel]()

    override func viewDidLoad() 
        super.viewDidLoad()

        //Adjust height of the lower Gray Line
        lowerGrayLine.frame.origin.y = 411

        //No dividing lines in the tableview initially
        self.tableView.separatorStyle = .none

        tableView.rowHeight = UITableViewAutomaticDimension
        tableView.estimatedRowHeight = 140

        if (self.tableView(self.tableView, numberOfRowsInSection: 0) > 0) 
        
            self.updateTableContentInset()
        

        // Allow for keyboard dismissal
        let tap: UITapGestureRecognizer = UITapGestureRecognizer(target: self, action: #selector(ViewController.dismissKeyboard))
        view.addGestureRecognizer(tap)

        NotificationCenter.default.addObserver(self, selector: #selector(ViewController.keyboardWillShow), name: NSNotification.Name.UIKeyboardWillShow, object: nil)
        NotificationCenter.default.addObserver(self, selector: #selector(ViewController.keyboardWillHide), name: NSNotification.Name.UIKeyboardWillHide, object: nil)

        // Show keyboard
        textField.becomeFirstResponder()
    

    func keyboardWillShow(notification: NSNotification) 
        if let keyboardSize = (notification.userInfo?[UIKeyboardFrameBeginUserInfoKey] as? NSValue)?.cgRectValue 
            //Adjust text box, and dividing line placement
            textField.frame.origin.y = 416
            lowerGrayLine.frame.origin.y = 411
        
    

    func keyboardWillHide(notification: NSNotification) 
        if let keyboardSize = (notification.userInfo?[UIKeyboardFrameBeginUserInfoKey] as? NSValue)?.cgRectValue 
            textField.frame.origin.y = 597
            lowerGrayLine.frame.origin.y = 557
        
    

    //Calls this function when the tap is recognized.
    func dismissKeyboard() 
        //Causes the view (or one of its embedded text fields) to resign the first responder status.
        view.endEditing(true)
    

    func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int 
        return self.fruits.count;
    

    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell 
        let cellIdentifier = "fruitCell"
        guard let cell = tableView.dequeueReusableCell(withIdentifier: cellIdentifier, for: indexPath) as? FruitTableViewCell else 
            fatalError("The dequeued cell is not an instance of FruitTableViewCell.")
        

        var fruitName = fruits[indexPath.row]
        var fruitNamename = fruitName.name

        var colon = ":"

        cell.nameLabel.text = fruitNamename + colon

        cell.fruitLabel.text = fruitName.fruit

        //Make some adjustments to make a line appear when a fruitCell is actually being shown
        cell.preservesSuperviewLayoutMargins = false
        cell.separatorInset = UIEdgeInsets.zero
        cell.layoutMargins = UIEdgeInsets.zero

        // This causes the bottom-most cell to not have a cell separator 
        if (indexPath.row == fruits.count-1) 
            cell.separatorInset = UIEdgeInsetsMake(0, cell.bounds.size.width, 0, 0);
        
        return cell
    

    func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat 
        return UITableViewAutomaticDimension
    

    // Adjust the tableView
    func updateTableContentInset() 
        let numRows = tableView(tableView, numberOfRowsInSection: 0)

        var contentInsetTop = tableView.bounds.size.height
        for i in 0..<numRows 
            contentInsetTop -= tableView(tableView, heightForRowAt: IndexPath(item: i, section: 0))
            if contentInsetTop <= 0 
                contentInsetTop = 0
            
        
        self.tableView.contentInset = UIEdgeInsetsMake(contentInsetTop, 0, 0, 0)
        self.tableView.scrollToRow(at: IndexPath(item: numRows-1, section: 0), at: .bottom, animated: false)
        //Prevent scrolling
        self.tableView.bounces = false;
        //When we have actual fruit Cells to show, we want the line divisions
        self.tableView.separatorStyle = .singleLine
    

我已尝试将以下代码添加到我的 keyboardWillShow 函数中:

var tableViewFrame: CGRect!
tableViewFrame = self.tableView.frame
tableViewFrame.size.height += 146.0
tableView.frame = tableViewFrame
tableView.contentInset = UIEdgeInsetsMake(146.0, 0, 0, 0);

但是,当键盘消失时,有横过屏幕的水平灰线,如下图:

编辑:

这些水平灰线(共六条)不应该存在。当键盘消失时,如何防止它们出现?

【问题讨论】:

你可以像***.com/a/50294205/4601900一样实现,它会使用inputAccessoryView所以你不需要担心tableview的高度 你能解释一下 inputAccessoryView 是如何工作的吗?它会让 tableview 成为键盘的附件吗? 由于 UIViewController 是 UIResonder 所以它可以是 firstResponder 【参考方案1】:

为此,您需要在keyboardWillHide 中编写代码:

    调整tableView的大小,增加键盘高度框架高度(或相对约束的常数值);

    关键点:设置tableView的top content inset等于键盘的高度。

例如,如果键盘的高度是 216pt,你会这样做:

CGRect tableViewFrame = tableView.frame;
tableViewFrame.size.height += 216.0;
tableView.frame = tableViewFrame;

tableView.contentInset = UIEdgeInsetsMake(216.0, 0, 0, 0);

如果您改用约束,唯一的区别是您将更改约束常量相对于tableView 高度的高度。

附:如果您想更深入地了解UIEdgeInsets 是什么,请看这里:https://developer.apple.com/documentation/uikit/uiedgeinsets 它们完全是为了创建具有特定偏移量的空白空间。

【讨论】:

我在上面添加了你的代码。但是,当表格视图消失时,屏幕上会出现水平灰线。我已经编辑了我的原始帖子,以包含在这种情况下我的屏幕外观的屏幕截图。相反,屏幕应该只是白色的。如何防止出现这些灰线?【参考方案2】:
    func keyboardWillShow(notification:NSNotification) 

          if let keyboardSize = notification.userInfo?[UIKeyboardFrameBeginUserInfoKey] as? CGRect 
        let contentInsets = UIEdgeInsets(top: 0, left: 0, bottom: 
         keyboardSize.height, right: 0)
        print(contentInsets)


        btnBottomConstrain.constant = contentInsets.bottom
        UIView.animate(withDuration: 0.2, delay: 0, options: .transitionCurlDown, animations: 
            self.view.layoutIfNeeded()
        , completion: nil)

    


func keyboardWillHide(notification:NSNotification) 



    if let keyboardSize = notification.userInfo?[UIKeyboardFrameBeginUserInfoKey] as? CGRect 
        let contentInsets = UIEdgeInsets(top: 0, left: 0, bottom: keyboardSize.height, right: 0)
        print(contentInsets)

        self.btnBottomConstrain.constant = 0

        UIView.animate(withDuration: 0.2, delay: 0, options: .transitionCurlDown, animations: 
            self.view.layoutIfNeeded()
        , completion: nil)


    

相应地用您的keyboardshow 和keybordhide 方法替换这两种方法。这里 btnBottomConstrain 将是您的 tableview 底部约束的出口。我希望这对你有用。

【讨论】:

我已经试过你上面的代码了。我在 tableview 和屏幕底部之间添加了一个底部约束,即底部布局指南。但是,添加这个之后,当键盘消失时,会出现横跨屏幕的水平灰线。不应有灰线。我已经编辑了我的原始帖子以包含这些灰线的屏幕截图。如何防止出现这些灰线? tableView为空时,隐藏即可。【参考方案3】:

最简单的解决方案是IQKeyboardManager。这将为您管理键盘下方的空间。

否则,将底部约束tableViewBottomConstraint 添加到表视图。设置其初始值tableViewBottomConstraint.constant = 0

现在设置它等于键盘高度 + keyboardWillShow keyboardWillHide 中的填充

func keyboardWillShow(notification: NSNotification) 
    tableViewBottomConstraint.constant = keyboardHeight + padding
    layoutTableView()


func keyboardWillHide(notification: NSNotification) 
    tableViewBottomConstraint.constant = 0
    layoutTableView()


private func layoutTableView() 
    UIView.animate(withDuration: 0.3, animations: 
        tableView.superview?.layoutIfNeeded()
    , completion: nil) 

【讨论】:

这个底部约束是否应该在tableview和它最近的下邻居之间,也就是水平灰线?或者,这个底部约束应该在tableview和整个屏幕的底部之间,也就是Bottom Layout Guide?​​span> 如果 tableView 下面没有任何其他元素/视图,那应该在 tableView 和底部布局指南之间。如果您在 tableView 下方有一个,那么底部约束应该在该元素和底部布局指南之间。

以上是关于键盘消失时增加Tableview的高度?的主要内容,如果未能解决你的问题,请参考以下文章

tableview 中的两个 TextFields,都在滚动视图上,当键盘出现 iPhone 时消失

使用Objective C增加Tableview高度时动态增加UIView高度?

当键盘出现iOS时向上滚动tableview行

在出现键盘时处理 tableView contentInset

根据 contentSize 增加 tableview 的高度

ContentInsets 不适用于 UITableView