键盘出现后布局中断

时间:2018-08-21 12:39:41

标签: ios swift uicollectionview

我建立了一个表格,用户可以在其中写下他的报告。当我单击textField时,将出现键盘,并且视图被弄乱了,我无法弄清为什么会这样。我也多次收到此错误消息。有关如何构建视图的一些信息。此collectionsView的单元格也是collectionViews,它们显示显示的视图(具有白色背景颜色的部分)。 gif末尾的浅蓝色(底部)是homeContoller collectionView的背景色。 buttonContainer是newReportCell对象的一部分,该对象是homeController collectionView内部的单元格。如果有人对如何解决此错误有个想法,那将非常有帮助。

  

2018-08-21 14:28:53.772211 + 0200 TestApp [91209:4755287]   未定义UICollectionViewFlowLayout的行为,因为:   2018-08-21 14:28:53.772389 + 0200 TestApp [91209:4755287]   项目高度必须小于UICollectionView的高度   减去该部分可插入顶部和底部的值,减去内容   插入顶部和底部值。 2018-08-21 14:28:53.772610 + 0200   TestApp [91209:4755287]相关   UICollectionViewFlowLayout实例为,并附加到;   层=; contentOffset:{768,0};   contentSize:{1536,858}; AdjustedContentInset:{0,0,263,0}>   集合视图布局:。   2018-08-21 14:28:53.772728 + 0200 TestApp [91209:4755287]   在以下位置建立符号断点   UICollectionViewFlowLayoutBreakForInvalidSizes可以在   调试器。

import UIKit

class HomeController: UICollectionViewController, UICollectionViewDelegateFlowLayout{

    let cellId = "cellId"
    let cellId2 = "cellId2"
    let appTitles = ["Test" , "TestView"]
    var currentIndexPath = IndexPath(item: 0, section: 0)

    lazy var menuBar: MenuBar = {
        let mb = MenuBar()
        mb.homeController = self
        mb.translatesAutoresizingMaskIntoConstraints = false
        return mb
    }()

    override func viewDidLoad() {
        super.viewDidLoad()
        initView()
    }

    func initView() {           
        navigationItem.title = "Test"
        navigationItem.leftBarButtonItem = UIBarButtonItem(title: "Logout", style: .plain, target: self, action: #selector(handleLogout))

        navigationController?.navigationBar.prefersLargeTitles = true


        setupMenuBar()
        setupCollectionView()
        setupMenuButtons()

        observeKeyboardNotifications()
    }

    func setupCollectionView() {

        if let flowLayout = collectionView?.collectionViewLayout as? UICollectionViewFlowLayout {
            flowLayout.scrollDirection = .horizontal
            flowLayout.minimumLineSpacing = 0
        }

        // blue background color
        collectionView?.backgroundColor = UIColor(r: 198, g: 225, b: 243)

        collectionView?.register(FeedCell.self, forCellWithReuseIdentifier: cellId)
        collectionView?.register(NewReportCell.self, forCellWithReuseIdentifier: cellId2)

        collectionView?.translatesAutoresizingMaskIntoConstraints = false
        collectionView?.topAnchor.constraint(equalTo: menuBar.bottomAnchor).isActive = true
        collectionView?.leadingAnchor.constraint(equalTo: view.leadingAnchor).isActive = true
        collectionView?.widthAnchor.constraint(equalTo: view.widthAnchor).isActive = true
        collectionView?.heightAnchor.constraint(equalTo: view.heightAnchor, constant: -166).isActive =  true
        collectionView?.isPagingEnabled = true
    }

    func setupMenuButtons() {
        let synchroImage = UIImage(named: "synchronize")
        let synchroBarButtonItem = UIBarButtonItem(image: synchroImage, style: .plain, target: self, action: #selector(handleSync))
        navigationItem.rightBarButtonItems = [synchroBarButtonItem]
    }

    private func setTitleForIndex(index: Int) {
        navigationItem.title = appTitles[Int(index)]
        dismissKeyboard()
    }

    @objc func dismissKeyboard() {
        self.view.endEditing(true)
    }

    override func scrollViewDidScroll(_ scrollView: UIScrollView) {
        menuBar.horizontalBarLeadingAnchorConstraint?.constant = scrollView.contentOffset.x / CGFloat(appTitles.count)
    }

    override func scrollViewWillEndDragging(_ scrollView: UIScrollView, withVelocity velocity: CGPoint, targetContentOffset: UnsafeMutablePointer<CGPoint>) {
        let index = targetContentOffset.pointee.x / view.frame.width

        let indexPath = IndexPath(item: Int(index), section: 0)
        currentIndexPath = indexPath
        menuBar.collectionView.selectItem(at: indexPath, animated: true, scrollPosition: [])

        setTitleForIndex(index: Int(index))
        self.invalidateLayoutForCell(index: Int(index))
    }

    func invalidateLayoutForCell(index: Int) {
        if index == 0 {
            self.feedCell?.invalidateLayout()
        } else {
            self.newReportCell?.invalidateLayout()
        }
    }

    override func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
        return appTitles.count
    }

    override func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
        if indexPath.item == 0{
            let cell = collectionView.dequeueReusableCell(withReuseIdentifier: cellId, for: indexPath) as! FeedCell
            cell.homeController = self
            feedCell = cell
            return cell
        }
        else {
            let cell = collectionView.dequeueReusableCell(withReuseIdentifier: cellId2, for: indexPath) as! NewReportCell
            cell.homeController = self
            newReportCell = cell
            return cell
        }
    }

    func pushViewController(controller: UICollectionViewController, animated: Bool) {
        navigationController?.pushViewController(controller, animated: animated)
    }

    func scrollToMenuIndex(menuIndex: Int) {
        let indexPath = IndexPath(item: menuIndex, section: 0)
        currentIndexPath = indexPath
        collectionView?.scrollToItem(at: indexPath, at: [], animated: true)

        setTitleForIndex(index: menuIndex)
        DispatchQueue.main.async {
        }
    }

    func invalidateLayout() {
        self.collectionView?.collectionViewLayout.invalidateLayout()


        DispatchQueue.main.async {
            self.collectionView?.scrollToItem(at: self.currentIndexPath, at: .centeredHorizontally, animated: true)
            self.menuBar.refreshView()
            self.feedCell?.invalidateLayout()
            self.newReportCell?.invalidateLayout()
        }
    }

    override func viewWillTransition(to size: CGSize, with coordinator: UIViewControllerTransitionCoordinator) {
        super.viewWillTransition(to: size, with: coordinator)
        invalidateLayout()
    }

    func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
        print(collectionView.frame.width, " - " , collectionView.frame.height)
        return CGSize(width: collectionView.frame.width, height: collectionView.frame.height)
    }


    private func setupMenuBar() {
        view.addSubview(menuBar)
        menuBar.leadingAnchor.constraint(equalTo: view.leadingAnchor).isActive = true
        menuBar.topAnchor.constraint(equalTo: view.safeAreaLayoutGuide.topAnchor).isActive = true
        menuBar.widthAnchor.constraint(equalTo: view.widthAnchor).isActive = true
        menuBar.heightAnchor.constraint(equalToConstant: 50).isActive = true
    }

    fileprivate func observeKeyboardNotifications() {
        NotificationCenter.default.addObserver(self, selector: #selector(keyboardShow), name: .UIKeyboardWillShow, object: nil)

        NotificationCenter.default.addObserver(self, selector: #selector(keyboardHide), name: .UIKeyboardWillHide, object: nil)
    }

    @objc func keyboardShow() {
        if(UIDevice.current.orientation == UIDeviceOrientation.landscapeLeft || UIDevice.current.orientation == UIDeviceOrientation.landscapeRight){
            UIView.animate(withDuration: 0.5, delay: 0, usingSpringWithDamping: 1, initialSpringVelocity: 1, options: .curveEaseOut, animations: {
                self.view.frame = CGRect(x: 0, y: -150, width: self.view.frame.width, height: self.view.frame.height)
            }, completion: nil)
        }
        else {
            UIView.animate(withDuration: 0.5, delay: 0, usingSpringWithDamping: 1, initialSpringVelocity: 1, options: .curveEaseOut, animations: {
                self.view.frame = CGRect(x: 0, y: -50, width: self.view.frame.width, height: self.view.frame.height)
            }, completion: nil)
        }
        print("keyboard shown")
    }

    @objc func keyboardHide() {
        UIView.animate(withDuration: 0.5, delay: 0, usingSpringWithDamping: 1, initialSpringVelocity: 1, options: .curveEaseOut, animations: {
            self.view.frame = CGRect(x: 0, y: 0, width: self.view.frame.width, height: self.view.frame.height)
        }, completion: nil)
        print("keyboard hide")
    }

}

layout crashes when keyboard appears

3 个答案:

答案 0 :(得分:1)

func keyboardWillShow(notification: NSNotification) {            
    if let keyboardSize = (notification.userInfo?[UIKeyboardFrameBeginUserInfoKey] as? NSValue)?.CGRectValue() {
        self.view.frame.origin.y -= keyboardSize.height
    }            
}

func keyboardWillHide(notification: NSNotification) {
    if let keyboardSize = (notification.userInfo?[UIKeyboardFrameBeginUserInfoKey] as? NSValue)?.CGRectValue() {
        self.view.frame.origin.y += keyboardSize.height
    }

尝试这两个功能可以在我的项目中使用,并且不会破坏您的布局

答案 1 :(得分:0)

  

希望这对您有帮助

要管理此问题,建议您使用IQKeyboardManagerSwift,它将处理您的键盘和文本字段。

答案 2 :(得分:0)

我想出了解决问题的方法。我将Mahesh Dangar的答案与Eduardo Irias(ios - How to get the height of Keyboard?)的答案结合在一起。当文本字段之一将pickerView作为inputView时,这将考虑安全区域并避免某些问题。视图将调整为键盘的高度。

var lastKeyboardHeight = CGFloat(0)

fileprivate func observeKeyboardNotifications() {
    NotificationCenter.default.addObserver(self, selector: #selector(keyboardWillShow), name: .UIKeyboardWillShow, object: nil)

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

@objc func keyboardWillShow(notification: NSNotification) {
    guard let keyboardFrame = notification.userInfo?[UIKeyboardFrameEndUserInfoKey] as? NSValue else {
        return
    }

    let keyboardHeight: CGFloat
    if #available(iOS 11.0, *) {
        keyboardHeight = keyboardFrame.cgRectValue.height - self.view.safeAreaInsets.bottom
    } else {
        keyboardHeight = keyboardFrame.cgRectValue.height
    }
    if lastKeyboardHeight != keyboardHeight {
        self.view.frame.origin.y += lastKeyboardHeight
    }
    else {
        return
    }
    self.view.frame.origin.y -= keyboardHeight
    lastKeyboardHeight = keyboardHeight
}

@objc func keyboardWillHide(notification: NSNotification) {
    guard let keyboardFrame = notification.userInfo?[UIKeyboardFrameEndUserInfoKey] as? NSValue else {
        return
    }

    let keyboardHeight: CGFloat
    if #available(iOS 11.0, *) {
        keyboardHeight = keyboardFrame.cgRectValue.height - self.view.safeAreaInsets.bottom
    } else {
        keyboardHeight = keyboardFrame.cgRectValue.height
    }
    self.view.frame.origin.y += keyboardHeight
    lastKeyboardHeight = 0
}