Нижний колонтитул UICollectionViewController неправильно позиционируется после завершения редактирования - PullRequest
0 голосов
/ 26 февраля 2019

У меня есть простой UICollectionViewController, который представляет собой один раздел с верхним и нижним колонтитулами, прикрепленными к видимым границам.Когда я щелкаю текстовое поле в нижнем колонтитуле, нижний колонтитул автоматически анимируется над клавиатурой и прокручивает collectionView, чтобы показать ячейки, которые в противном случае были бы скрыты клавиатурой, как и следовало ожидать.Однако, когда я щелкаю один за пределами клавиатуры и отклоняю его вызовом self.view.endEditing(true), нижний колонтитул и collectionView не реагируют, если collectionView не прокручивается внизу.Если collectionView прокручивается внизу, нижний колонтитул и collectionView анимируются, как и ожидалось.

Как заставить каждый нижний колонтитул и collectionView корректно анимироваться каждый раз?

В изображениях ниже заголовокоранжевый, нижний колонтитул зеленый, и есть 10 ячеек, чередующихся красный и синий.

Фактическое поведение (происходит, когда вы не прокручиваетесь в нижней части окна collectionView, когда клавиатура отклоняется) actual behavior

Желаемое поведение (происходит, когда вы прокручиваете в нижней части коллекции или около нее, когда клавиатура отклоняется) desired behavior

Я знаю, что есть некоторыеметоды для достижения этого с помощью уведомлений, когда клавиатура появляется и исчезает, но я бы предпочел просто использовать поведение UICollectionViewController по умолчанию, если это возможно.Мне не хватает какой-либо конфигурации или настройки?

Код: Новое приложение Single View.Удалите StoryBoard и ViewController.swift.Удалите основную запись раскадровки из файла сведений.

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 Ответ

0 голосов
/ 26 февраля 2019

Из документации:

func 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()
    }
}
...