【问题标题】:inputAccessoryView not respecting safeAreaLayoutGuide when keyboard is collapsed键盘折叠时 inputAccessoryView 不遵守 safeAreaLayoutGuide
【发布时间】:2021-05-09 12:26:06
【问题描述】:

我正在尝试让 inputAccessoryView 正常工作。也就是说,在这种情况下,我希望能够以两种可能的状态显示 UIToolbar:

  1. 键盘上方 - 标准和预期行为
  2. 当键盘被关闭时在屏幕底部(例如模拟器中的 command + K) - 在这种情况下,让 bottomAnchor 尊重底部的 safeAreaLayoutGuide。

我已经广泛研究了这个主题,但我能找到的每一个建议都有一堆似乎与 Apple 工程建议的解决方案不一致的解决方法。根据 openradar 票证,Apple 工程人员提出了以下解决方案:

您有责任尊重输入附件视图的 安全区域插图。我们以这种方式设计它,以便开发人员可以提供 背景视图(即,参见 Safari 的 Find on Page 输入附件视图) 并根据 safeAreaInsets 布置内容视图。这是 相当容易完成。有一个视图层次结构 有一个容器视图和一个内容视图。容器视图可以有 背景颜色或包含其全部内容的背景视图 bounds,它基于 safeAreaInsets 布局它的内容视图。如果 您正在使用自动布局,这就像设置内容一样简单 view的bottomAnchor等于它的superview 安全区域布局指南。

以上链接为:http://www.openradar.me/34411433

因此,我构建了一个简单的 xCode 项目(iOS App 模板),其中包含以下代码:

class ViewController: UIViewController {
    
    var field = UITextField()
    var containerView = UIView()
    var contentView = UIView()
    var toolbar = UIToolbar()
    
    override func viewDidLoad() {
        super.viewDidLoad()
    
        // TEXTFIELD
        field = UITextField(frame: CGRect(x: 20, y: 100, width: view.frame.size.width, height: 50))
        field.placeholder = "Enter name..."
        field.backgroundColor = .secondarySystemBackground
        field.inputAccessoryView = containerView
        view.addSubview(field)
        
        // CONTAINER VIEW
        containerView.frame = CGRect(x: 0, y: 0, width: view.frame.size.width, height: 50)
        containerView.backgroundColor = .systemYellow
        containerView.translatesAutoresizingMaskIntoConstraints = false
                
        // CONTENT VIEW
        contentView.frame = CGRect(x: 0, y: 0, width: view.frame.size.width, height: 50)
        contentView.backgroundColor = .systemPink
        contentView.translatesAutoresizingMaskIntoConstraints = false
        containerView.addSubview(contentView)
        
        // TOOLBAR
        toolbar = UIToolbar(frame: CGRect(x: 0, y: 0, width: view.frame.size.width, height: 50))
        let flexibleSpace = UIBarButtonItem(barButtonSystemItem: .flexibleSpace, target: self, action: nil)
        let doneButton = UIBarButtonItem(title: "Done", style: .done, target: self, action: #selector(didTapDone))
        toolbar.setItems([flexibleSpace, doneButton], animated: true)
        toolbar.backgroundColor = .systemGreen
        toolbar.translatesAutoresizingMaskIntoConstraints = false
        contentView.addSubview(toolbar)
        
        NSLayoutConstraint.activate([
            contentView.topAnchor.constraint(equalTo: containerView.topAnchor),
            contentView.leadingAnchor.constraint(equalTo: containerView.leadingAnchor),
            contentView.trailingAnchor.constraint(equalTo: containerView.trailingAnchor),
            contentView.bottomAnchor.constraint(equalTo: contentView.superview!.safeAreaLayoutGuide.bottomAnchor),

            toolbar.topAnchor.constraint(equalTo: contentView.topAnchor),
            toolbar.leadingAnchor.constraint(equalTo: contentView.leadingAnchor),
            toolbar.trailingAnchor.constraint(equalTo: contentView.trailingAnchor),
            toolbar.bottomAnchor.constraint(equalTo: contentView.bottomAnchor),
        ])
    }
    
    
    @objc private func didTapDone() {
        print("done tapped")
    }
}

结果在键盘可见时有效,但在键盘关闭后无效:

我玩弄了各种视图的高度,结果混合在一起,并使容器视图框架高度更大(例如 100),当键盘折叠时确实显示工具栏,它也使工具栏太高键盘是可见的。

很明显,我遇到了一些自动布局约束问题,但我无法解决问题,如果有任何反馈可以提供符合 Apple 建议的有效解决方案,我将不胜感激。

提前致谢。

【问题讨论】:

    标签: ios swift autolayout inputaccessoryview


    【解决方案1】:

    就我而言,我使用以下方法:

    import UIKit
    
    extension UIView {
        
        
        
       
        
        func setDimensions(height: CGFloat, width: CGFloat) {
            translatesAutoresizingMaskIntoConstraints = false
            heightAnchor.constraint(equalToConstant: height).isActive = true
            widthAnchor.constraint(equalToConstant: width).isActive = true
        }
        
        func setHeight(_ height: CGFloat) {
            translatesAutoresizingMaskIntoConstraints = false
            heightAnchor.constraint(equalToConstant: height).isActive = true
        }
    }
    
    
    
    class CustomTextField: UITextField {
        override init(frame: CGRect) {
            super.init(frame: frame)
        }
        
        convenience init(placeholder: String) {
            self.init(frame: .zero)
            configureUI(placeholder: placeholder)
        }
        
        required init?(coder: NSCoder) {
            fatalError("init(coder:) has not been implemented")
        }
        
        func configureUI(placeholder: String) {
            
            let spacer = UIView()
            spacer.setDimensions(height: 50, width: 12)
            leftView = spacer
            leftViewMode = .always
            
            borderStyle = .none
            textColor = .white
            keyboardAppearance = .dark
            backgroundColor = UIColor(white: 1, alpha: 0.1)
            setHeight(50)
            attributedPlaceholder = NSAttributedString(string: placeholder, attributes: [.foregroundColor: UIColor(white: 1, alpha: 0.75)])
            
            
        }
    }
    
     
    

    【讨论】:

    • 问题不在于文本字段的位置。问题是视图层次结构中的工具栏被添加为 textField 的 inputAccessoryView
    • 您是否尝试设置工具栏尺寸约束?因为我看到你给了工具栏初始框架,但随后将 translatesAutoresizingMaskIntoConstraints 设置为 false
    • 是的,然后在下面应用约束
    • O, ok 在提供的代码中没有找到heightAnchor / widthAnchor
    • 向工具栏添加高度约束会导致自动布局错误,然后它会选择通过打破该约束来恢复。所以我认为问题出在其他地方......
    【解决方案2】:

    我能够通过包装工具栏(在我的例子中是聊天输入栏)并将其限制在 top/right/left + bottom 到包装器的安全区域来实现效果。

    我会在下面留下一个大概的食谱。

    在您的视图控制器中:

    override var inputAccessoryView: UIView? {
        keyboardHelper
    }
        
    override var canBecomeFirstResponder: Bool {
        true
    }
    
    lazy var keyboardHelper: InputBarWrapper = {
        let wrapper = InputBarWrapper()
        let inputBar = InputBar()
        helper.addSubview(inputBar)
        inputBar.translatesAutoresizingMaskIntoConstraints = false
        NSLayoutConstraint.activate([
            inputBar.topAnchor.constraint(equalTo: helper.topAnchor),
            inputBar.leftAnchor.constraint(equalTo: helper.leftAnchor),
            inputBar.bottomAnchor.constraint(equalTo:
    helper.safeAreaLayoutGuide.bottomAnchor),
            inputBar.rightAnchor.constraint(equalTo: helper.rightAnchor),
        ])
        
        return wrapper
    }()
    

    工具栏包装子类:

    class InputBarWrapper: UIView {
            
        var desiredHeight: CGFloat = 0 {
            didSet { invalidateIntrinsicContentSize() }
        }
        
        override var intrinsicContentSize: CGSize {
            CGSize(width: 0, height: desiredHeight)
        }
        
        required init?(coder aDecoder: NSCoder) {
            fatalError()
        }
        
        override init(frame: CGRect) {
            super.init(frame: frame);
            autoresizingMask = .flexibleHeight
            backgroundColor = UIColor.systemGreen.withAlphaComponent(0.2)
        }
    
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-05-20
      • 2015-01-28
      • 2018-10-27
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多