UICollectionViewController 页脚在 endEditing 后无法正确重新定位
Posted
技术标签:
【中文标题】UICollectionViewController 页脚在 endEditing 后无法正确重新定位【英文标题】:UICollectionViewController footer not re-positioning itself properly after endEditing 【发布时间】:2019-02-26 19:50:07 【问题描述】:我有一个简单的 UICollectionViewController,它是一个带有固定到可见边界的页眉和页脚的部分。当我单击页脚中的 textField 时,页脚会自动在键盘上方进行动画处理,并且 collectionView 会滚动以显示否则会如您所料被键盘隐藏的单元格。但是,当我单击键盘外部的一个并通过调用self.view.endEditing(true)
将其关闭时,除非在底部附近滚动collectionView,否则页脚和collectionView 不会做出反应。如果 collectionView 在底部附近滚动,则页脚和 collectionView 会按预期进行动画处理。
如何强制页脚和 collectionView 每次都正确设置动画?
在下图中,页眉为橙色,页脚为绿色,并且有 10 个单元格以红色和蓝色交替显示。
实际行为(当键盘关闭时您未在 collectionView 底部附近滚动时发生)
期望的行为(当您在键盘关闭时在 collectionView 底部或附近滚动时发生)
我知道有一些方法可以在键盘出现和消失时使用通知来实现这一点,但如果可能的话,我宁愿只使用默认的 UICollectionViewController 行为。是否缺少某些配置或设置?
代码: 新的单一视图应用程序。删除 StoryBoard 和 ViewController.swift。从 info plist 文件中删除主情节提要条目。
AppDelegate.swift
import UIKit
@UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate
var window: UIWindow?
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool
window = UIWindow(frame: UIScreen.main.bounds)
window?.makeKeyAndVisible()
window?.rootViewController = CollectionViewController.init()
return true
CollectionViewController.swift
import UIKit
private let reuseIdentifier = "Cell"
private let collectionViewHeaderFooterReuseIdentifier = "MyHeaderFooterClass"
class CollectionViewController: UICollectionViewController
init()
let collectionViewFlowLayout = UICollectionViewFlowLayout.init()
collectionViewFlowLayout.sectionHeadersPinToVisibleBounds = true
collectionViewFlowLayout.sectionFootersPinToVisibleBounds = true
super.init(collectionViewLayout: collectionViewFlowLayout)
required init?(coder aDecoder: NSCoder)
fatalError("init(coder:) has not been implemented")
override func viewWillAppear(_ animated: Bool)
super.viewWillAppear(animated)
override func viewWillDisappear(_ animated: Bool)
super.viewWillDisappear(animated)
override func viewDidLoad()
super.viewDidLoad()
// Register cell classes
self.collectionView?.register(UICollectionViewCell.self, forCellWithReuseIdentifier: reuseIdentifier)
self.collectionView?.register(MyHeaderFooterClass.self, forSupplementaryViewOfKind: UICollectionView.elementKindSectionHeader, withReuseIdentifier: collectionViewHeaderFooterReuseIdentifier)
self.collectionView?.register(MyHeaderFooterClass.self, forSupplementaryViewOfKind: UICollectionView.elementKindSectionFooter, withReuseIdentifier: collectionViewHeaderFooterReuseIdentifier)
self.collectionView?.backgroundColor = UIColor.white
self.collectionView?.dataSource = self
self.collectionView?.delegate = self
// MARK: UICollectionViewDelegate
extension CollectionViewController
override func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath)
DispatchQueue.main.async
self.view.endEditing(true)
self.collectionViewLayout.invalidateLayout()
self.collectionView?.layoutIfNeeded()
// MARK: - UICollectionViewDataSource
extension CollectionViewController
override func numberOfSections(in collectionView: UICollectionView) -> Int
// #warning Incomplete implementation, return the number of sections
return 1
override func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int
// #warning Incomplete implementation, return the number of items
return 10
override func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: reuseIdentifier, for: indexPath)
switch indexPath.row % 2
case 0:
cell.backgroundColor = UIColor.red
case 1:
cell.backgroundColor = UIColor.blue
default:
cell.backgroundColor = UIColor.gray
return cell
override func collectionView(_ collectionView: UICollectionView, viewForSupplementaryElementOfKind kind: String, at indexPath: IndexPath) -> UICollectionReusableView
let view = collectionView.dequeueReusableSupplementaryView(ofKind: kind, withReuseIdentifier: collectionViewHeaderFooterReuseIdentifier, for: indexPath)
if kind == UICollectionView.elementKindSectionHeader
view.backgroundColor = UIColor.orange
else //footer
view.backgroundColor = UIColor.green
return view
// MARK: - Collection View Flow Layout Delegate
extension CollectionViewController: UICollectionViewDelegateFlowLayout
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize
return CGSize(width: collectionView.frame.width, height: 100)
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, insetForSectionAt section: Int) -> UIEdgeInsets
return UIEdgeInsets(top: 0, left: 0, bottom: 0, right: 0)
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, minimumLineSpacingForSectionAt section: Int) -> CGFloat
return 0
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, referenceSizeForHeaderInSection section: Int) -> CGSize
return CGSize(width: collectionView.frame.width, height: 100)
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, referenceSizeForFooterInSection section: Int) -> CGSize
return CGSize(width: collectionView.frame.width, height: 100)
MyHeaderFooterClass
import UIKit
class MyHeaderFooterClass: UICollectionReusableView
let textField: UITextField =
let view = UITextField.init()
view.placeholder = "enter text here"
view.translatesAutoresizingMaskIntoConstraints = false
return view
()
override init(frame: CGRect)
super.init(frame: frame)
self.addSubview(textField)
self.setNeedsUpdateConstraints()
override func updateConstraints()
textFieldConstraints()
super.updateConstraints()
private func textFieldConstraints()
NSLayoutConstraint(item: textField, attribute: .top, relatedBy: .equal, toItem: self, attribute: .top, multiplier: 1.0, constant: 0.0).isActive = true
NSLayoutConstraint(item: textField, attribute: .left, relatedBy: .equal, toItem: self, attribute: .left, multiplier: 1.0, constant: 0.0).isActive = true
NSLayoutConstraint(item: textField, attribute: .right, relatedBy: .equal, toItem: self, attribute: .right, multiplier: 1.0, constant: 0.0).isActive = true
NSLayoutConstraint(item: textField, attribute: .bottom, relatedBy: .equal, toItem: self, attribute: .bottom, multiplier: 1.0, constant: 0.0).isActive = true
required init?(coder aDecoder: NSCoder)
fatalError("init(coder:) has not been implemented")
【问题讨论】:
你看到我发布的答案了吗? 嘿对不起,是的,我做到了。这确实解决了页脚卡在页面中间的问题,但单元格本身并没有滑回以匹配它。所以无论如何我都必须实施不同的机制。感谢您的帮助,您确实回答了最初的问题,所以我现在会接受您的回答。 【参考方案1】:来自文档:
函数 layoutIfNeeded()
使用此方法强制视图立即更新其布局。
func invalidateLayout()
此方法使集合视图的布局本身无效,并且 立即返回。
解决方案:
查看您的代码,您已经在更新collectionViewLayout
。因此,您无需再次强制更新collectionView
。因此,仅删除 self.collectionView?.layoutIfNeeded() 即可解决您的问题。
如下修改你的代码:
override func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath)
DispatchQueue.main.async
self.view.endEditing(true)
self.collectionViewLayout.invalidateLayout()
//self.collectionView?.layoutIfNeeded()
【讨论】:
以上是关于UICollectionViewController 页脚在 endEditing 后无法正确重新定位的主要内容,如果未能解决你的问题,请参考以下文章