i have a Problem with my UICollectionView inside my Swift Xcode Project I checked all insets and margins, I tried the ViewController's: "Adjust Scroll View Insets" and lots of other stuff, but none of them did change this in any way.
i want to reduce / remove that top spacing above the first row of cells in my collectionView
I created a sample project to find a solution/fix for this issue, but didn't had any luck yet
This seems to be a issue when using a Collection View inserted via Storyboard /Interface builder, because this does not happen if I add the collectionView on the code side
Here's my View Controller's Code:
import UIKit
struct CVData: Hashable {
var name: String
var value: String
}
class ViewController: UIViewController {
@IBOutlet weak var myCollectionView: UICollectionView!
var dataSource: UICollectionViewDiffableDataSource<Section, CVData>!
var cvDataList: [CVData] = []
enum Section {
case main
}
var CVDataLabels: [String] = ["Label1:","Label2:","Label3:","Label4:","Label5:","Label6:","Label7:","Label8:"]
var CVDataValues: [String] = []
var snapshot: NSDiffableDataSourceSnapshot<Section, CVData>!
override func viewDidLoad() {
super.viewDidLoad()
configureCollectionView()
buildData()
// Do any additional setup after loading the view.
}
func configureCollectionView() {
let layoutConfig = UICollectionLayoutListConfiguration(appearance: .insetGrouped)
let listLayout = UICollectionViewCompositionalLayout.list(using: layoutConfig)
myCollectionView.collectionViewLayout = listLayout
myCollectionView.isScrollEnabled = false
let cellRegistration = UICollectionView.CellRegistration<UICollectionViewListCell, CVData> { (cell, indexPath, item) in
var content = UIListContentConfiguration.cell()
content.text = item.name
content.textProperties.font.withSize(8.0)
content.textProperties.font = UIFont.preferredFont(forTextStyle: .body)
content.secondaryText = item.value
content.prefersSideBySideTextAndSecondaryText = true
content.textProperties.adjustsFontSizeToFitWidth = false
cell.contentConfiguration = content
}
dataSource = UICollectionViewDiffableDataSource<Section, CVData>(collectionView: myCollectionView) {
(collectionView: UICollectionView, indexPath: IndexPath, identifier: CVData) -> UICollectionViewCell? in
// Dequeue reusable cell using cell registration (Reuse identifier no longer needed)
let cell = collectionView.dequeueConfiguredReusableCell(using: cellRegistration,
for: indexPath,
item: identifier)
// Configure cell appearance
cell.accessories = [.disclosureIndicator()]
return cell
}
}
func buildData() {
let cvDataList = [
CVData(name: self.CVDataLabels[0], value: "value1"),
CVData(name: self.CVDataLabels[1], value: "value2"),
CVData(name: self.CVDataLabels[2], value: "value3"),
CVData(name: self.CVDataLabels[3], value: "value4"),
CVData(name: self.CVDataLabels[4], value: "value5"),
CVData(name: self.CVDataLabels[5], value: "value6"),
CVData(name: self.CVDataLabels[6], value: "value6"), //added 20210510
CVData(name: self.CVDataLabels[7], value: "value7")
]
// Create a snapshot that define the current state of data source's data
self.snapshot = NSDiffableDataSourceSnapshot<Section, CVData>()
self.snapshot.appendSections([.main])
self.snapshot.appendItems(cvDataList, toSection: .main)
// Display data in the collection view by applying the snapshot to data source
self.dataSource.apply(self.snapshot, animatingDifferences: false)
}
}
Here's the Size inspector settings from that UICOllectionView
Any help'd be greatly appreciated đź‘Ť
I haven't worked with UICollectionViewCompositionalLayout.list
, so this is just from some quick research and experimentation...
The default .headerMode
for UICollectionLayoutListConfiguration
is .none
... when using .insetGrouped
that results in the "extra space" we're seeing.
Curiously, there is also a headerTopPadding
property, which we might expect to be of help here. It's default is 0
... but that appears to only be applied if there IS a header view.
So, if we set .headerMode = .supplementary
and return an empty UICollectionReusableView
for the header, we can get rid of the extra space:
Now, the top space is the same as the default left/right padding.
Here's what I used for the header view:
class EmptyHeaderView : UICollectionReusableView {
static let reuseIdentifier:String = "emptyHeaderView"
}
and three edits to your configureCollectionView()
func:
func configureCollectionView() {
var layoutConfig = UICollectionLayoutListConfiguration(appearance: .insetGrouped)
// 1
// we're going to supply an "empty" header supplementary view
layoutConfig.headerMode = .supplementary
let listLayout = UICollectionViewCompositionalLayout.list(using: layoutConfig)
myCollectionView.collectionViewLayout = listLayout
myCollectionView.isScrollEnabled = false
let cellRegistration = UICollectionView.CellRegistration<UICollectionViewListCell, CVData> { (cell, indexPath, item) in
var content = UIListContentConfiguration.cell()
content.text = item.name
content.textProperties.font.withSize(8.0)
content.textProperties.font = UIFont.preferredFont(forTextStyle: .body)
content.secondaryText = item.value
content.prefersSideBySideTextAndSecondaryText = true
content.textProperties.adjustsFontSizeToFitWidth = false
cell.contentConfiguration = content
}
dataSource = UICollectionViewDiffableDataSource<Section, CVData>(collectionView: myCollectionView) {
(collectionView: UICollectionView, indexPath: IndexPath, identifier: CVData) -> UICollectionViewCell? in
// Dequeue reusable cell using cell registration (Reuse identifier no longer needed)
let cell = collectionView.dequeueConfiguredReusableCell(using: cellRegistration,
for: indexPath,
item: identifier)
// Configure cell appearance
cell.accessories = [.disclosureIndicator()]
return cell
}
// 2
// register a reusable supplementary view for the header
myCollectionView.register(EmptyHeaderView.self, forSupplementaryViewOfKind: UICollectionView.elementKindSectionHeader, withReuseIdentifier: EmptyHeaderView.reuseIdentifier)
// 3
// provider for header suppleentary view
dataSource.supplementaryViewProvider = { (collectionView: UICollectionView, kind: String, indexPath: IndexPath) -> UICollectionReusableView? in
if kind == UICollectionView.elementKindSectionHeader {
if let headerView = collectionView.dequeueReusableSupplementaryView(ofKind: kind, withReuseIdentifier: EmptyHeaderView.reuseIdentifier, for: indexPath) as? EmptyHeaderView {
return headerView
}
}
fatalError("Something's wrong with the setup...")
}
}