微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

键盘折叠时 inputAccessoryView 不尊重 safeAreaLayoutGuide

如何解决键盘折叠时 inputAccessoryView 不尊重 safeAreaLayoutGuide

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

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

我对这个主题进行了广泛的研究,但我能找到的每一个建议都有一堆似乎与 Apple 工程建议的解决方案不一致的解决方法。基于 openradar 票证,Apple 工程部提出了以下解决方案:

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

以上链接是: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,height: 50)
        containerView.backgroundColor = .systemYellow
        containerView.translatesAutoresizingMaskIntoConstraints = false
                
        // CONTENT VIEW
        contentView.frame = CGRect(x: 0,height: 50)
        contentView.backgroundColor = .systemPink
        contentView.translatesAutoresizingMaskIntoConstraints = false
        containerView.addSubview(contentView)
        
        // TOOLBAR
        toolbar = UIToolbar(frame: CGRect(x: 0,height: 50))
        let flexibleSpace = UIBarButtonItem(barButtonSystemItem: .flexibleSpace,target: self,action: nil)
        let doneButton = UIBarButtonItem(title: "Done",style: .done,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")
    }
}

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

keyboard visible

enter image description here

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

很明显,我正在解决一些自动布局约束问题,但我无法解决,并且希望能提供与 Apple 建议一致的可行解决方案的任何反馈。

提前致谢。

解决方法

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

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)])
        
        
    }
}

 
,

我能够通过包装工具栏(在我的例子中为聊天输入栏)并将其限制为 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)
    }

}

enter image description here

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。