为什么滚动 collection view 后视图消失了?

Why does the view disappear after scrolling through the collection view?

我正在尝试创建一个在键盘出现时向上滑动的视图,在该视图中有一个文本字段用作搜索栏和集合视图以保存搜索结果。视图在键盘上方正常滑动,就像它应该的那样,但是一旦我点击其中一个单元格水平滚动,视图就会消失。可能是什么原因造成的。

我认为可能导致问题的代码

var offsetY:CGFloat = 0

override func viewWillAppear(_ animated: Bool) {
    super.viewWillAppear(animated)
    NotificationCenter.default.addObserver(self, selector: #selector(ViewController.keyboardFrameChangeNotification(notification:)), name: NSNotification.Name.UIKeyboardWillChangeFrame, object: nil)
}



@objc func keyboardFrameChangeNotification(notification: Notification) {
    if let userInfo = notification.userInfo {
        let endFrame = userInfo[UIKeyboardFrameEndUserInfoKey] as? CGRect
        let animationDuration = userInfo[UIKeyboardAnimationDurationUserInfoKey] as? Double ?? 0
        let animationCurveRawValue = (userInfo[UIKeyboardAnimationCurveUserInfoKey] as? Int) ?? Int(UIViewAnimationOptions.curveEaseInOut.rawValue)
       let animationCurve = UIViewAnimationOptions(rawValue: Int(animationCurveRawValue))
        if let _ = endFrame, endFrame!.intersects(self.myView.frame) {
            self.offsetY = self.myView.frame.maxY - endFrame!.minY
            UIView.animate(withDuration: animationDuration, delay: TimeInterval(0), options: animationCurve, animations: {
                self.myView.frame.origin.y = self.myView.frame.origin.y - self.offsetY
            }, completion: nil)
        } else {
            if self.offsetY != 0 {
                UIView.animate(withDuration: animationDuration, delay: TimeInterval(0), options: animationCurve, animations: {
                    self.myView.frame.origin.y = self.myView.frame.origin.y + self.offsetY
                    self.offsetY = 0
                }, completion: nil)
            }
        }
    }
}

完整代码

import UIKit

class SearchCollectionViewController: UIViewController,UICollectionViewDelegate,UICollectionViewDelegateFlowLayout, UITextFieldDelegate, UICollectionViewDataSource {

@IBOutlet weak var searchBar: UITextField!
@IBOutlet weak var collectionView: UICollectionView!

@IBOutlet weak var myView: UIView!


var genericArray:[String] = ["A","B","C","D","E","F","G","Ab","Abc"]
var currentGenericArray:[String] = [String]()

override func viewDidLoad() {
    super.viewDidLoad()
    collectionView.delegate = self
    collectionView.dataSource = self
    let layout: UICollectionViewFlowLayout = UICollectionViewFlowLayout()
    layout.sectionInset = UIEdgeInsets(top: 0, left: 0, bottom: 10, right: 0)
    layout.itemSize = CGSize(width: (UIScreen.main.bounds.width-1)/2, height: (UIScreen.main.bounds.width-1)/2)
    layout.minimumInteritemSpacing = 1
    layout.minimumLineSpacing = 1
    layout.scrollDirection = .horizontal
    self.collectionView.collectionViewLayout = layout


    searchBar.delegate = self
    currentGenericArray = genericArray
    searchBar.addTarget(self, action: #selector(TableSearchViewController.textFieldDidChange), for: .editingChanged)



}

@objc func textFieldDidChange(){
    guard(!(searchBar.text?.isEmpty)!) else{
        currentGenericArray = genericArray
        collectionView.reloadData()
        return
    }
    currentGenericArray = genericArray.filter({letter -> Bool in
        letter.lowercased().contains(searchBar.text!)
    })
    collectionView.reloadData()
}


func numberOfSections(in collectionView: UICollectionView) -> Int {
    return 1
}

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

func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
    let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "collectionViewCell", for: indexPath) as! CollectionCell

    cell.collectionLabel.text = currentGenericArray[indexPath.row]

    return cell
}

func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, minimumLineSpacingForSectionAt section: Int) -> CGFloat {
    return 0
}

var offsetY:CGFloat = 0

override func viewWillAppear(_ animated: Bool) {
    super.viewWillAppear(animated)
    NotificationCenter.default.addObserver(self, selector: #selector(ViewController.keyboardFrameChangeNotification(notification:)), name: NSNotification.Name.UIKeyboardWillChangeFrame, object: nil)
}



@objc func keyboardFrameChangeNotification(notification: Notification) {
    if let userInfo = notification.userInfo {
        let endFrame = userInfo[UIKeyboardFrameEndUserInfoKey] as? CGRect
        let animationDuration = userInfo[UIKeyboardAnimationDurationUserInfoKey] as? Double ?? 0
        let animationCurveRawValue = (userInfo[UIKeyboardAnimationCurveUserInfoKey] as? Int) ?? Int(UIViewAnimationOptions.curveEaseInOut.rawValue)
        let animationCurve = UIViewAnimationOptions(rawValue: UInt(animationCurveRawValue))
        if let _ = endFrame, endFrame!.intersects(self.myView.frame) {
            self.offsetY = self.myView.frame.maxY - endFrame!.minY
            UIView.animate(withDuration: animationDuration, delay: TimeInterval(0), options: animationCurve, animations: {
                self.myView.frame.origin.y = self.myView.frame.origin.y - self.offsetY
            }, completion: nil)
        } else {
            if self.offsetY != 0 {
                UIView.animate(withDuration: animationDuration, delay: TimeInterval(0), options: animationCurve, animations: {
                    self.myView.frame.origin.y = self.myView.frame.origin.y + self.offsetY
                    self.offsetY = 0
                }, completion: nil)
            }
        }
    }
}

}


class CollectionCell:UICollectionViewCell{

@IBOutlet weak var collectionLabel: UILabel!

override func awakeFromNib() {
    collectionLabel.textAlignment = .center

}
}

您的代码有点混乱,但除了您从 searchBar 调用的 didChange 之外,我没有看到任何 textField 函数。尝试添加 shouldReturndidEndEditing,并更新您的滑块。这是我会做的一个例子。尝试一下,看看它是否有所作为。

Lifecycle

   let keyboardSlider = KeyboardSlider()

   override func viewDidLoad() { 
       super.viewDidLoad()
       keyboardSlider.subscribeToKeyboardNotifications(view: view) 
    }

    override func viewWillDisappear(_ animated: Bool) {
        super.viewWillDisappear(animated)
        keyboardSlider.unsubscribeFromKeyboardNotifications()
    }

TextField

// MARK: TextFieldDelegate
func textFieldDidBeginEditing(_ textField: UITextField) {
    // Add Done button  for Keyboard Dismissal

    let toolBar = UIToolbar()
    toolBar.sizeToFit()
    toolBar.barStyle = .default
    let doneButton = UIBarButtonItem(barButtonSystemItem: .done, target: self, action: #selector(self.didStopEditing))
    let space = UIBarButtonItem(barButtonSystemItem: .flexibleSpace, target: self, action: nil)
    toolBar.setItems([space, doneButton], animated: false)
    textField.inputAccessoryView = toolBar
}


func textFieldShouldReturn(_ textField: UITextField) -> Bool {
    textField.resignFirstResponder()
    return true
}

/// Helper to dismiss keyboard
@objc func didStopEditing() {
    textFieldShouldReturn(phoneNumberTextField)
}

func textFieldDidEndEditing(_ textField: UITextField) { 
    UIView.setAnimationCurve(UIViewAnimationCurve.easeInOut)
        UIView.animate(withDuration: 0.2) {
            self.view.frame.origin.y = 0
        }
}

Keyboard Slider

class KeyboardSlider: NSObject {
        // variables to hold and process information from the view using this class
    weak var view: UIView?

    @objc func keyboardWillShow(notification: NSNotification) {
        // method to move keyboard up
        view?.frame.origin.y = 0 - getKeyboardHeight(notification as Notification)
    }

    func getKeyboardHeight(_ notification:Notification) -> CGFloat {
        // get exact height of keyboard on all devices and convert to float value to return for use
        let userInfo = notification.userInfo
        let keyboardSize = userInfo![UIKeyboardFrameEndUserInfoKey] as! NSValue
        return keyboardSize.cgRectValue.height
    }

    func subscribeToKeyboardNotifications(view: UIView) {
        // assigning view to class' counterpart
        self.view = view
        // when UIKeyboardWillShow do keyboardWillShow function
        NotificationCenter.default.addObserver(self, selector: #selector(keyboardWillShow(notification:)), name: .UIKeyboardWillShow, object: nil)
    }

    func unsubscribeFromKeyboardNotifications() {
        NotificationCenter.default.removeObserver(self, name: .UIKeyboardWillShow, object: nil)
    }


}

This answer is mainly to clean up your code

我感觉您的问题出在您的 didChange 键盘关闭方法中。清理您的代码并单步执行断点将有助于找到您的问题。