我正在尝试创建一个在键盘出现时向上滑动的视图,并且在此视图中有一个文本字段用作搜索栏和集合视图来保存搜索结果。视图在键盘上方滑动得很好,但是一旦我点击其中一个单元格以可怕地滚动,视图就会消失。可能导致这种情况的原因是什么。
我认为可能导致问题的代码
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
}
}
你的代码有点混乱,但我没有看到任何textField
函数,除了你从searchBar
调用的didChange
。尝试添加shouldReturn
和didEndEditing
,以及更新滑块。这是我会做什么的一个例子。尝试一下,看看它是否有所作为。
生命周期
let keyboardSlider = KeyboardSlider()
override func viewDidLoad() {
super.viewDidLoad()
keyboardSlider.subscribeToKeyboardNotifications(view: view)
}
override func viewWillDisappear(_ animated: Bool) {
super.viewWillDisappear(animated)
keyboardSlider.unsubscribeFromKeyboardNotifications()
}
文本字段
// 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
}
}
键盘滑块
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)
}
}
这个答案主要是清理你的代码
我有一种感觉,你的问题出在你didChange
键盘关闭的方法上。清理代码并单步执行断点将有助于找到问题。