The behavior of the UICollectionViewFlowLayout is not defined because:
the item width must be less than the width of the UICollectionView minus the section insets left and right values, minus the content insets left and right values.
Эта ошибка возникает при повороте экране. Уже который день мучаюсь с этой ошибкой. Весь интернет уже обшарил… Прикол в том, что ширина точно не выходит за рамки… и почему-то это происходит только с одной коллекцией, а с другими коллекциями все нормально. Так о чем это говорит все же?
Вот фул код проекта (создал отдельным проектом):
import UIKit
class MainViewController: UIViewController {
let profileButtons = ProfileButtons(collectionViewLayout: UICollectionViewLayout())
override func viewDidLoad() {
super.viewDidLoad()
setButtonsCollection()
}
private func setButtonsCollection() // меню
{
addChild(profileButtons)
view.addSubview(profileButtons.view)
profileButtons.didMove(toParent: self)
profileButtons.view.translatesAutoresizingMaskIntoConstraints = false
profileButtons.view.topAnchor.constraint(equalTo: view.topAnchor, constant: 0).isActive = true
profileButtons.view.leftAnchor.constraint(equalTo: view.leftAnchor, constant: 0).isActive = true
profileButtons.view.rightAnchor.constraint(equalTo: view.rightAnchor, constant: 0).isActive = true
profileButtons.view.heightAnchor.constraint(equalToConstant: profileButtons.cvHeight).isActive = true
}
}
import UIKit
struct ProfileButtonsSection {
let title: String
let items: [ProfileButtonsItems]
}
struct ProfileButtonsItems {
let isNav: Bool
let name: String
let image: UIImage
}
class ProfileButtonsFlowLayout: UICollectionViewFlowLayout {
// override func shouldInvalidateLayout(forBoundsChange: CGRect) -> Bool
// {
// super.shouldInvalidateLayout(forBoundsChange: forBoundsChange)
//
// return false
// }
}
class ProfileButtons: UICollectionViewController, UICollectionViewDelegateFlowLayout {
public let flowLayout = ProfileButtonsFlowLayout()
private let sections: [ProfileButtonsSection] = [
ProfileButtonsSection(
title : "Аккаунт",
items : [
ProfileButtonsItems(isNav : false, name: "Тестовое название", image: #imageLiteral(resourceName: "wallet")),
ProfileButtonsItems(isNav : true, name: "Тестовое название", image: #imageLiteral(resourceName: "clock")),
ProfileButtonsItems(isNav : false, name: "Тестовое название", image: #imageLiteral(resourceName: "coeffFormat")),
]
),
ProfileButtonsSection(
title : "Безопасность",
items : [
ProfileButtonsItems(isNav : true, name: "Изменить пароль", image: #imageLiteral(resourceName: "pass")),
ProfileButtonsItems(isNav : true, name: "Двухфакторная аутентификация", image: #imageLiteral(resourceName: "protect")),
]
),
ProfileButtonsSection(
title : "Помощь",
items : [
ProfileButtonsItems(isNav : true, name: "Служба поддержки", image: #imageLiteral(resourceName: "support")),
ProfileButtonsItems(isNav : true, name: "Правила и условия", image: #imageLiteral(resourceName: "list")),
ProfileButtonsItems(isNav : true, name: "Тестовое название", image: #imageLiteral(resourceName: "license")),
]
),
ProfileButtonsSection(
title : "",
items : [
ProfileButtonsItems(isNav : false, name: "Тестовое название", image: #imageLiteral(resourceName: "star2")),
ProfileButtonsItems(isNav : false, name: "Выход", image: #imageLiteral(resourceName: "exit")),
]
),
]
// имя переиспользуемого заголовка/подвала
private let headerId = "header"
private let footerId = "footer"
// имя переиспользуемой ячейки
private let cellId = "cell"
// высота ячейки
private let cellHeight: CGFloat = 40
// высота заголовка секции
private let headerHeight: CGFloat = 40
// высота футера секции
private let footerHeight: CGFloat = 20
// высота коллекции
public var cvHeight: CGFloat {
var itemsCount: Int = 0
for (value) in sections
{
itemsCount += value.items.count
}
let sectionCount = sections.count - 1 // не учитывать последнюю секции
let cvHeight = ( Int(headerHeight) * sectionCount ) + (Int(cellHeight) * itemsCount) + (Int(footerHeight) * sectionCount)
return CGFloat(cvHeight)
}
var width: CGFloat!
override func viewDidLoad() {
super.viewDidLoad()
// минимальное расстояние между ячейками (по основной оси)
flowLayout.minimumInteritemSpacing = 0
// минимальное расстояние между ячейками (по поперечной оси)
flowLayout.minimumLineSpacing = 0
// отступы для секций
flowLayout.sectionInset = UIEdgeInsets(top: 0, left: 0, bottom: 0, right: 0)
// направление заполнения ячеек
flowLayout.scrollDirection = .vertical
//flowLayout.estimatedItemSize = UICollectionViewFlowLayout.automaticSize
//flowLayout.itemSize = CGSize(width: collectionView.frame.width, height: cellHeight)
collectionView = UICollectionView(frame: .zero, collectionViewLayout: flowLayout)
collectionView.register(ProfileButtonCell.self, forCellWithReuseIdentifier: cellId)
collectionView.register(ProfileButtonSectionHeader.self, forSupplementaryViewOfKind: UICollectionView.elementKindSectionHeader, withReuseIdentifier: headerId)
collectionView.register(ProfileButtonSectionFooter.self, forSupplementaryViewOfKind: UICollectionView.elementKindSectionFooter, withReuseIdentifier: footerId)
collectionView.backgroundColor = .clear
width = collectionView.frame.width
}
override func viewWillTransition(to size: CGSize, with coordinator: UIViewControllerTransitionCoordinator) {
super.viewWillTransition(to: size, with: coordinator)
//print(collectionView.frame.width, size.width)
//flowLayout.itemSize.width = size.width
width = size.width
print("viewWillTransition")
flowLayout.invalidateLayout()
}
// кол-во секций
override func numberOfSections(in collectionView: UICollectionView) -> Int {
return sections.count
}
// кол-во ячеек в секции
override func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return sections[section].items.count
}
// возвращает секцию
// override func collectionView(_ collectionView: UICollectionView, viewForSupplementaryElementOfKind kind: String, at indexPath: IndexPath) -> UICollectionReusableView {
// switch kind {
// case UICollectionView.elementKindSectionHeader:
//
// let header = collectionView.dequeueReusableSupplementaryView(ofKind: kind, withReuseIdentifier: headerId, for: indexPath as IndexPath) as! ProfileButtonSectionHeader
//
// let section = sections[indexPath.section]
//
// header.label.text = section.title.uppercased()
//
// return header
//
// case UICollectionView.elementKindSectionFooter:
// let footer = collectionView.dequeueReusableSupplementaryView(ofKind: kind, withReuseIdentifier: footerId, for: indexPath as IndexPath)
//
// return footer
//
// default:
// return UICollectionReusableView()
// }
// }
// возвращает ячейку
override func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: cellId, for: indexPath) as! ProfileButtonCell
let item = sections[indexPath.section].items[indexPath.row]
if !item.isNav
{
cell.imageNavNext.isHidden = true
}
cell.image.image = item.image
cell.label.text = item.name
return cell
}
// размер секции заголовка
// func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, referenceSizeForHeaderInSection section: Int) -> CGSize {
//
// return sections.count-1 == section ? CGSize(width: 0, height: 0) : CGSize(width: collectionView.frame.width, height: headerHeight)
// }
//
// // размер секции футера
// func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, referenceSizeForFooterInSection section: Int) -> CGSize {
//
// return sections.count-1 == section ? CGSize(width: 0, height: 0) : CGSize(width: collectionView.frame.width, height: footerHeight)
// }
//
// размер ячейки
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
print("sizeForItemAt")
return CGSize(width: width, height: cellHeight)
}
}
// верхний колонтитул секции
class ProfileButtonSectionHeader: UICollectionReusableView {
let label: UILabel = {
let label = UILabel()
label.translatesAutoresizingMaskIntoConstraints = false
label.textColor = .systemGray
label.font = UIFont(descriptor: UIFontDescriptor.init(name: "Google Sans Regular", size: 0), size: 12)
return label
}()
override init(frame: CGRect) {
super.init(frame: frame)
addSubview(label)
}
required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
override func layoutSubviews() {
super.layoutSubviews()
label.topAnchor.constraint(equalTo: self.topAnchor, constant: 0).isActive = true
label.leftAnchor.constraint(equalTo: self.safeAreaLayoutGuide.leftAnchor, constant: 20).isActive = true
label.rightAnchor.constraint(equalTo: self.safeAreaLayoutGuide.rightAnchor, constant: 0).isActive = true
label.bottomAnchor.constraint(equalTo: self.bottomAnchor, constant: 0).isActive = true
}
}
// нижний колонтитул секциии
class ProfileButtonSectionFooter: UICollectionReusableView {
let borderTop: UIView = {
let borderTop = UIView()
borderTop.backgroundColor = UIColor(red: 255/255, green: 255/255, blue: 255/255, alpha: 0.1)
borderTop.translatesAutoresizingMaskIntoConstraints = false
return borderTop
}()
override init(frame: CGRect) {
super.init(frame: frame)
addSubview(borderTop)
}
required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
override func layoutSubviews() {
super.layoutSubviews()
borderTop.leftAnchor.constraint(equalTo: self.safeAreaLayoutGuide.leftAnchor, constant: 20).isActive = true
borderTop.rightAnchor.constraint(equalTo: self.safeAreaLayoutGuide.rightAnchor, constant: -20).isActive = true
borderTop.heightAnchor.constraint(equalToConstant: 1).isActive = true
borderTop.centerYAnchor.constraint(equalTo: self.centerYAnchor, constant: 0).isActive = true
}
}
// ячейка
class ProfileButtonCell: UICollectionViewCell {
override var isHighlighted: Bool {
didSet {
let bgColor = isHighlighted ? UIColor(red: 255/255, green: 255/255, blue: 255/255, alpha: 0.1) : UIColor.clear
self.backgroundColor = bgColor
}
}
let label: UILabel = {
let label = UILabel()
label.translatesAutoresizingMaskIntoConstraints = false
label.textColor = .white
label.font = UIFont(descriptor: UIFontDescriptor.init(name: "Google Sans Regular", size: 0), size: 14)
return label
}()
let image: UIImageView = {
let image = UIImageView()
image.translatesAutoresizingMaskIntoConstraints = false
image.contentMode = .scaleAspectFit
image.tintColor = .gray
return image
}()
let imageNavNext: UIImageView = {
let image = UIImageView()
image.image = #imageLiteral(resourceName: "nav-next")
image.translatesAutoresizingMaskIntoConstraints = false
image.contentMode = .scaleAspectFit
image.tintColor = .gray
return image
}()
override init(frame: CGRect) {
super.init(frame: frame)
contentView.addSubview(image)
contentView.addSubview(label)
contentView.addSubview(imageNavNext)
image.widthAnchor.constraint(equalToConstant: 17).isActive = true
image.heightAnchor.constraint(equalToConstant: 17).isActive = true
image.leftAnchor.constraint(equalTo: contentView.safeAreaLayoutGuide.leftAnchor, constant: 20).isActive = true
image.centerYAnchor.constraint(equalTo: contentView.centerYAnchor).isActive = true
label.topAnchor.constraint(equalTo: contentView.topAnchor, constant: 0).isActive = true
label.bottomAnchor.constraint(equalTo: contentView.bottomAnchor, constant: 0).isActive = true
label.leftAnchor.constraint(equalTo: image.leftAnchor, constant: 30).isActive = true
label.widthAnchor.constraint(greaterThanOrEqualToConstant: 0).isActive = true
imageNavNext.widthAnchor.constraint(equalToConstant: 11).isActive = true
imageNavNext.heightAnchor.constraint(equalToConstant: 11).isActive = true
imageNavNext.rightAnchor.constraint(equalTo: contentView.safeAreaLayoutGuide.rightAnchor, constant: -20).isActive = true
imageNavNext.centerYAnchor.constraint(equalTo: contentView.centerYAnchor).isActive = true
}
required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
}
Текущий код, который я скинул, работает для iphone 8 и ниже, но с ворнингом:
[App] if we’re in the real pre-commit handler we can’t actually add any new fences due to CA restriction
Для iphone 10 и выше не работает…
Но хочу заметить, что работает все корректно! Читал, что эти предупреждения или ошибки безвредны… но все же… почему тогда они не возникают в других коллекциях?