在 iOS 中模拟提醒应用“添加”页脚

Posted

技术标签:

【中文标题】在 iOS 中模拟提醒应用“添加”页脚【英文标题】:Emulating the Reminders App "Add" Footer in iOS 【发布时间】:2017-02-03 13:48:40 【问题描述】:

我可以使用一些指针来尝试创建类似于 iPhone 上的提醒应用程序的“添加”页脚,无论是通过 Interface Builder 和/或代码。

更具体地说,我有一个数据列表,并希望有一个始终可用的可编辑“添加”行,如下所示:

当列表底部可见时,您会在底部看到“添加” 当不可见时,“添加”行浮动并在视图底部保持可见/可访问 显示键盘时,“添加”行位于键盘正上方

到目前为止,我已经尝试使用表格视图控制器并将 EditFieldView 放在表格页脚中。这需要照顾一个功能。但是如果不编写代码,我不确定从那里去哪里。我对 ios UI 还是有点陌生​​,希望避免重新发明已经存在的功能。

【问题讨论】:

Reminders 正在使用键盘附件在键盘上方显示“添加”按钮。它很可能会监听键盘通知并隐藏并显示表格页脚。你也可以让你的桌子用键盘调整它的框架,所以如果它实际上是一个页脚,那么你的页脚也会向上移动。没什么特别的。 【参考方案1】:

使您的视图位于键盘上方但在键盘不可见时仍位于表格底部的示例。

我添加了一个红色的 UIView。当您点击它时,键盘将显示,您可以看到它动画到键盘上方的位置。当您点击单元格本身时,您可以看到键盘关闭并且视图移回表格底部。

还有其他方法可以做到这一点,例如使用键盘附件视图和附加到底部的视图。不过,我不会深入。

使用键盘通知的示例:

//
//  ViewController.swift
//  SO
//
//  Created by Brandon T on 2017-02-03.
//  Copyright © 2017 XIO. All rights reserved.
//

import UIKit

class ViewController: UIViewController, UITableViewDataSource, UITableViewDelegate 

    var table: UITableView!
    var tableFooter: UIView!
    var bottomConstraint: NSLayoutConstraint!
    var dummyTextField: UITextField?

    deinit 
        NotificationCenter.default.removeObserver(self)
    

    override func viewDidLoad() 
        super.viewDidLoad()

        //Notifications
        NotificationCenter.default.addObserver(self, selector: #selector(keyboardWillShow(notification:)), name:NSNotification.Name.UIKeyboardWillShow, object: nil)

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

        //Setup Views
        self.table = UITableView(frame: self.view.frame, style: .grouped)
        self.table.delegate = self
        self.table.dataSource = self


        self.tableFooter = UIView()
        self.tableFooter.backgroundColor = UIColor.red
        let recognizer = UITapGestureRecognizer(target: self, action: #selector(onViewTap(recognizer:)))
        recognizer.numberOfTapsRequired = 1
        recognizer.numberOfTouchesRequired = 1
        self.tableFooter.addGestureRecognizer(recognizer)


        //Constraints
        self.view.addSubview(self.table)
        self.view.addSubview(self.tableFooter)

        self.table.leftAnchor.constraint(equalTo: self.view.leftAnchor).isActive = true
        self.table.rightAnchor.constraint(equalTo: self.view.rightAnchor).isActive = true
        self.table.topAnchor.constraint(equalTo: self.view.topAnchor).isActive = true

        self.tableFooter.leftAnchor.constraint(equalTo: self.view.leftAnchor).isActive = true
        self.tableFooter.rightAnchor.constraint(equalTo: self.view.rightAnchor).isActive = true
        self.tableFooter.topAnchor.constraint(equalTo: self.table.bottomAnchor).isActive = true
        self.tableFooter.heightAnchor.constraint(equalToConstant: 50.0).isActive = true
        self.bottomConstraint = self.tableFooter.bottomAnchor.constraint(equalTo: self.view.bottomAnchor)
        self.bottomConstraint.isActive = true


        self.table.translatesAutoresizingMaskIntoConstraints = false
        self.tableFooter.translatesAutoresizingMaskIntoConstraints = false
    

    override func didReceiveMemoryWarning() 
        super.didReceiveMemoryWarning()
    


    func keyboardWillShow(notification: Notification) 
        if let userInfo = notification.userInfo 
            let endFrame = (userInfo[UIKeyboardFrameEndUserInfoKey] as? NSValue)?.cgRectValue
            let duration:TimeInterval = (userInfo[UIKeyboardAnimationDurationUserInfoKey] as? NSNumber)?.doubleValue ?? 0
            let animationCurveRawNSN = userInfo[UIKeyboardAnimationCurveUserInfoKey] as? NSNumber
            let animationCurveRaw = animationCurveRawNSN?.uintValue ?? UIViewAnimationOptions.curveEaseInOut.rawValue
            let animationCurve:UIViewAnimationOptions = UIViewAnimationOptions(rawValue: animationCurveRaw)

            self.view.layoutIfNeeded()

            UIView.animate(withDuration: duration, delay: TimeInterval(0), options: animationCurve, animations: 
                if (self.bottomConstraint.constant <= 0.0) 
                    self.bottomConstraint.constant = -endFrame!.size.height
                
                self.view.layoutIfNeeded()
            , completion:  (finished) in

            )
        
    

    func keyboardWillHide(notification: Notification) 
        if let userInfo = notification.userInfo 
            let endFrame = (userInfo[UIKeyboardFrameEndUserInfoKey] as? NSValue)?.cgRectValue
            let duration:TimeInterval = (userInfo[UIKeyboardAnimationDurationUserInfoKey] as? NSNumber)?.doubleValue ?? 0
            let animationCurveRawNSN = userInfo[UIKeyboardAnimationCurveUserInfoKey] as? NSNumber
            let animationCurveRaw = animationCurveRawNSN?.uintValue ?? UIViewAnimationOptions.curveEaseInOut.rawValue
            let animationCurve:UIViewAnimationOptions = UIViewAnimationOptions(rawValue: animationCurveRaw)

            self.view.layoutIfNeeded()

            UIView.animate(withDuration: duration, delay: TimeInterval(0), options: animationCurve, animations: 
                self.bottomConstraint.constant = 0.0
                self.view.layoutIfNeeded()
            , completion:  (finished) in

            )
        
    


    //TableView
    func numberOfSections(in tableView: UITableView) -> Int 
        return 1
    

    func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int 
        return 10
    

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

    func tableView(_ tableView: UITableView, heightForHeaderInSection section: Int) -> CGFloat 
        return 0.00001
    

    func tableView(_ tableView: UITableView, heightForFooterInSection section: Int) -> CGFloat 
        return 0.00001
    

    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell 
        var cell = tableView.dequeueReusableCell(withIdentifier: "cellID")

        if (cell == nil) 
            cell = UITableViewCell(style: .default, reuseIdentifier: "cellID")
            cell!.selectionStyle = .none

            self.dummyTextField = UITextField(frame: CGRect(x: 100, y: 25.0, width: 100, height: 50))
            cell!.contentView.addSubview(self.dummyTextField!)
        

        cell!.backgroundColor = UIColor.white
        cell!.textLabel?.text = "Test - \(indexPath.row)"



        return cell!
    

    func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) 
        self.dummyTextField!.resignFirstResponder()
        self.dummyTextField!.endEditing(true)

        self.view.resignFirstResponder()
        self.view.endEditing(true)
    

    func onViewTap(recognizer: UITapGestureRecognizer) 
        self.dummyTextField?.becomeFirstResponder()
    

【讨论】:

感谢您为我指明了正确的方向。我正在更彻底地研究附件视图。

以上是关于在 iOS 中模拟提醒应用“添加”页脚的主要内容,如果未能解决你的问题,请参考以下文章

如何向 UITableViewController 添加粘性页脚?

iOS 8:将视图作为应用程序中所有视图控制器的页脚通用

拆分视图控制器中的 iOS 静态页脚

如何在ListView中添加页脚?

如何在 ListView 中添加页脚?

如何在 UITableView 中制作最终页脚?