UICollection뷰 열 수 설정
저는 이제 막 UI Collection Views에 대해 배우기 시작했습니다.컬렉션 뷰에서 열 수를 지정하는 방법을 아는 사람이 있는지 궁금합니다.기본값은 3(iPhone/portrait)으로 설정됩니다.서류를 봤는데, 간결한 답을 찾을 수가 없네요.
Swift 5와 iOS 12.3에서, 당신은 당신의 행당 항목의 수를 설정하기 위해 하나를 사용할 수 있습니다.UICollectionView
인셋 및 크기 변경(회전 포함)을 관리하는 동안
# 분류 #1. 하위 분류UICollectionViewFlowLayout
및사용을 사용합니다.UICollectionViewFlowLayout
의 재산
ColumnFlowLayout.swift:
import UIKit
class ColumnFlowLayout: UICollectionViewFlowLayout {
let cellsPerRow: Int
init(cellsPerRow: Int, minimumInteritemSpacing: CGFloat = 0, minimumLineSpacing: CGFloat = 0, sectionInset: UIEdgeInsets = .zero) {
self.cellsPerRow = cellsPerRow
super.init()
self.minimumInteritemSpacing = minimumInteritemSpacing
self.minimumLineSpacing = minimumLineSpacing
self.sectionInset = sectionInset
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
override func prepare() {
super.prepare()
guard let collectionView = collectionView else { return }
let marginsAndInsets = sectionInset.left + sectionInset.right + collectionView.safeAreaInsets.left + collectionView.safeAreaInsets.right + minimumInteritemSpacing * CGFloat(cellsPerRow - 1)
let itemWidth = ((collectionView.bounds.size.width - marginsAndInsets) / CGFloat(cellsPerRow)).rounded(.down)
itemSize = CGSize(width: itemWidth, height: itemWidth)
}
override func invalidationContext(forBoundsChange newBounds: CGRect) -> UICollectionViewLayoutInvalidationContext {
let context = super.invalidationContext(forBoundsChange: newBounds) as! UICollectionViewFlowLayoutInvalidationContext
context.invalidateFlowLayoutDelegateMetrics = newBounds.size != collectionView?.bounds.size
return context
}
}
CollectionViewController.swift:
import UIKit
class CollectionViewController: UICollectionViewController {
let columnLayout = ColumnFlowLayout(
cellsPerRow: 5,
minimumInteritemSpacing: 10,
minimumLineSpacing: 10,
sectionInset: UIEdgeInsets(top: 10, left: 10, bottom: 10, right: 10)
)
override func viewDidLoad() {
super.viewDidLoad()
collectionView?.collectionViewLayout = columnLayout
collectionView?.contentInsetAdjustmentBehavior = .always
collectionView?.register(UICollectionViewCell.self, forCellWithReuseIdentifier: "Cell")
}
override func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return 59
}
override func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "Cell", for: indexPath)
cell.backgroundColor = UIColor.orange
return cell
}
}
# #2 사용하기 사용하기UICollectionViewFlowLayout
의 방법
import UIKit
class CollectionViewController: UICollectionViewController {
let margin: CGFloat = 10
let cellsPerRow = 5
override func viewDidLoad() {
super.viewDidLoad()
guard let collectionView = collectionView, let flowLayout = collectionViewLayout as? UICollectionViewFlowLayout else { return }
flowLayout.minimumInteritemSpacing = margin
flowLayout.minimumLineSpacing = margin
flowLayout.sectionInset = UIEdgeInsets(top: margin, left: margin, bottom: margin, right: margin)
collectionView.contentInsetAdjustmentBehavior = .always
collectionView.register(UICollectionViewCell.self, forCellWithReuseIdentifier: "Cell")
}
override func viewWillLayoutSubviews() {
guard let collectionView = collectionView, let flowLayout = collectionView.collectionViewLayout as? UICollectionViewFlowLayout else { return }
let marginsAndInsets = flowLayout.sectionInset.left + flowLayout.sectionInset.right + collectionView.safeAreaInsets.left + collectionView.safeAreaInsets.right + flowLayout.minimumInteritemSpacing * CGFloat(cellsPerRow - 1)
let itemWidth = ((collectionView.bounds.size.width - marginsAndInsets) / CGFloat(cellsPerRow)).rounded(.down)
flowLayout.itemSize = CGSize(width: itemWidth, height: itemWidth)
}
override func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return 59
}
override func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "Cell", for: indexPath)
cell.backgroundColor = UIColor.orange
return cell
}
override func viewWillTransition(to size: CGSize, with coordinator: UIViewControllerTransitionCoordinator) {
collectionView?.collectionViewLayout.invalidateLayout()
super.viewWillTransition(to: size, with: coordinator)
}
}
# #3 사용하기 사용하기UICollectionViewDelegateFlowLayout
의 방법
import UIKit
class CollectionViewController: UICollectionViewController, UICollectionViewDelegateFlowLayout {
let inset: CGFloat = 10
let minimumLineSpacing: CGFloat = 10
let minimumInteritemSpacing: CGFloat = 10
let cellsPerRow = 5
override func viewDidLoad() {
super.viewDidLoad()
collectionView?.contentInsetAdjustmentBehavior = .always
collectionView?.register(UICollectionViewCell.self, forCellWithReuseIdentifier: "Cell")
}
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, insetForSectionAt section: Int) -> UIEdgeInsets {
return UIEdgeInsets(top: inset, left: inset, bottom: inset, right: inset)
}
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, minimumLineSpacingForSectionAt section: Int) -> CGFloat {
return minimumLineSpacing
}
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, minimumInteritemSpacingForSectionAt section: Int) -> CGFloat {
return minimumInteritemSpacing
}
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
let marginsAndInsets = inset * 2 + collectionView.safeAreaInsets.left + collectionView.safeAreaInsets.right + minimumInteritemSpacing * CGFloat(cellsPerRow - 1)
let itemWidth = ((collectionView.bounds.size.width - marginsAndInsets) / CGFloat(cellsPerRow)).rounded(.down)
return CGSize(width: itemWidth, height: itemWidth)
}
override func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return 59
}
override func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "Cell", for: indexPath)
cell.backgroundColor = UIColor.orange
return cell
}
override func viewWillTransition(to size: CGSize, with coordinator: UIViewControllerTransitionCoordinator) {
collectionView?.collectionViewLayout.invalidateLayout()
super.viewWillTransition(to: size, with: coordinator)
}
}
# 분류 #4. 하위 분류UICollectionViewFlowLayout
및사용을 사용합니다.UICollectionViewFlowLayout
의 재산
CollectionViewController.swift:
import UIKit
class CollectionViewController: UICollectionViewController {
let items = [
"Lorem ipsum dolor sit amet, consectetur adipiscing elit.",
"Lorem ipsum dolor sit amet, consectetur.",
"Lorem ipsum dolor sit amet.",
"Lorem ipsum dolor sit amet, consectetur.",
"Lorem ipsum dolor sit amet, consectetur adipiscing.",
"Lorem ipsum.",
"Lorem ipsum dolor sit amet.",
"Lorem ipsum dolor sit.",
"Lorem ipsum dolor sit amet, consectetur adipiscing.",
"Lorem ipsum dolor sit amet, consectetur adipiscing elit.",
"Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor.",
"Lorem ipsum dolor sit amet, consectetur."
]
let columnLayout = FlowLayout(
cellsPerRow: 3,
minimumInteritemSpacing: 10,
minimumLineSpacing: 10,
sectionInset: UIEdgeInsets(top: 10, left: 10, bottom: 10, right: 10)
)
override func viewDidLoad() {
super.viewDidLoad()
collectionView?.collectionViewLayout = columnLayout
collectionView?.contentInsetAdjustmentBehavior = .always
collectionView?.register(Cell.self, forCellWithReuseIdentifier: "Cell")
}
override func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return items.count
}
override func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "Cell", for: indexPath) as! Cell
cell.label.text = items[indexPath.row]
return cell
}
override func viewWillTransition(to size: CGSize, with coordinator: UIViewControllerTransitionCoordinator) {
collectionView?.collectionViewLayout.invalidateLayout()
super.viewWillTransition(to: size, with: coordinator)
}
}
FlowLayout.swift:
import UIKit
class FlowLayout: UICollectionViewFlowLayout {
let cellsPerRow: Int
required init(cellsPerRow: Int = 1, minimumInteritemSpacing: CGFloat = 0, minimumLineSpacing: CGFloat = 0, sectionInset: UIEdgeInsets = .zero) {
self.cellsPerRow = cellsPerRow
super.init()
self.minimumInteritemSpacing = minimumInteritemSpacing
self.minimumLineSpacing = minimumLineSpacing
self.sectionInset = sectionInset
estimatedItemSize = UICollectionViewFlowLayout.automaticSize
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
override func layoutAttributesForItem(at indexPath: IndexPath) -> UICollectionViewLayoutAttributes? {
guard let layoutAttributes = super.layoutAttributesForItem(at: indexPath) else { return nil }
guard let collectionView = collectionView else { return layoutAttributes }
let marginsAndInsets = collectionView.safeAreaInsets.left + collectionView.safeAreaInsets.right + sectionInset.left + sectionInset.right + minimumInteritemSpacing * CGFloat(cellsPerRow - 1)
layoutAttributes.bounds.size.width = ((collectionView.bounds.width - marginsAndInsets) / CGFloat(cellsPerRow)).rounded(.down)
return layoutAttributes
}
override func layoutAttributesForElements(in rect: CGRect) -> [UICollectionViewLayoutAttributes]? {
let superLayoutAttributes = super.layoutAttributesForElements(in: rect)!.map { $0.copy() as! UICollectionViewLayoutAttributes }
guard scrollDirection == .vertical else { return superLayoutAttributes }
let layoutAttributes = superLayoutAttributes.compactMap { layoutAttribute in
return layoutAttribute.representedElementCategory == .cell ? layoutAttributesForItem(at: layoutAttribute.indexPath) : layoutAttribute
}
// (optional) Uncomment to top align cells that are on the same line
/*
let cellAttributes = layoutAttributes.filter({ $0.representedElementCategory == .cell })
for (_, attributes) in Dictionary(grouping: cellAttributes, by: { ($0.center.y / 10).rounded(.up) * 10 }) {
guard let max = attributes.max(by: { $0.size.height < $1.size.height }) else { continue }
for attribute in attributes where attribute.size.height != max.size.height {
attribute.frame.origin.y = max.frame.origin.y
}
}
*/
// (optional) Uncomment to bottom align cells that are on the same line
/*
let cellAttributes = layoutAttributes.filter({ $0.representedElementCategory == .cell })
for (_, attributes) in Dictionary(grouping: cellAttributes, by: { ($0.center.y / 10).rounded(.up) * 10 }) {
guard let max = attributes.max(by: { $0.size.height < $1.size.height }) else { continue }
for attribute in attributes where attribute.size.height != max.size.height {
attribute.frame.origin.y += max.frame.maxY - attribute.frame.maxY
}
}
*/
return layoutAttributes
}
}
셀.swift:
import UIKit
class Cell: UICollectionViewCell {
let label = UILabel()
override init(frame: CGRect) {
super.init(frame: frame)
label.numberOfLines = 0
backgroundColor = .orange
contentView.addSubview(label)
label.translatesAutoresizingMaskIntoConstraints = false
label.topAnchor.constraint(equalTo: contentView.layoutMarginsGuide.topAnchor).isActive = true
label.leadingAnchor.constraint(equalTo: contentView.layoutMarginsGuide.leadingAnchor).isActive = true
label.trailingAnchor.constraint(equalTo: contentView.layoutMarginsGuide.trailingAnchor).isActive = true
label.bottomAnchor.constraint(equalTo: contentView.layoutMarginsGuide.bottomAnchor).isActive = true
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
override func preferredLayoutAttributesFitting(_ layoutAttributes: UICollectionViewLayoutAttributes) -> UICollectionViewLayoutAttributes {
layoutIfNeeded()
label.preferredMaxLayoutWidth = label.bounds.size.width
layoutAttributes.bounds.size.height = contentView.systemLayoutSizeFitting(UIView.layoutFittingCompressedSize).height
return layoutAttributes
}
// Alternative implementation
/*
override func preferredLayoutAttributesFitting(_ layoutAttributes: UICollectionViewLayoutAttributes) -> UICollectionViewLayoutAttributes {
label.preferredMaxLayoutWidth = layoutAttributes.size.width - contentView.layoutMargins.left - contentView.layoutMargins.right
layoutAttributes.bounds.size.height = contentView.systemLayoutSizeFitting(UIView.layoutFittingCompressedSize).height
return layoutAttributes
}
*/
}
CollectionView는 매우 강력하며 가격도 저렴합니다.많은 옵션들이 있습니다.아솜즈가 말했습니다.
열 수를 변경할 수 있는 여러 가지 방법이 있습니다.
프로토콜을 구현하여 다음 방법에 대한 액세스 권한을 부여하여 레이아웃을 보다 효과적으로 제어할 수 있도록 하는 것이 좋습니다.UICollectionView
하위 분류할 필요 없이:
collectionView:layout:insetForSectionAtIndex:
collectionView:layout:minimumInteritemSpacingForSectionAtIndex:
collectionView:layout:minimumLineSpacingForSectionAtIndex:
collectionView:layout:referenceSizeForFooterInSection:
collectionView:layout:referenceSizeForHeaderInSection:
collectionView:layout:sizeForItemAtIndexPath:
또한 다음 방법을 구현하면 UICollectionView가 방향 변경 시 레이아웃을 업데이트합니다. (셀 크기를 조정하고 확장하려고 했다고 가정합니다.)
-(void)willRotateToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation
duration:(NSTimeInterval)duration{
[self.myCollectionView.collectionViewLayout invalidateLayout];
}
추가로, 여기에 2개의 정말 좋은 튜토리얼이 있습니다.UICollectionViews
:
http://www.raywenderlich.com/22324/beginning-uicollectionview-in-ios-6-part-12
http://skeuo.com/uicollectionview-custom-layout-tutorial
는 구습니다를 했습니다.UICollectionViewDelegateFlowLayout
돈으로UICollectionViewController
셀 크기 결정을 담당하는 방법을 무시합니다.그런 다음 화면 너비를 제 컬럼 요구 사항과 함께 분할했습니다.예를 들어, 각 화면 크기에 3개의 열이 있기를 원했습니다. 제 - 제코는이니다렇습드다니.
- (CGSize)collectionView:(UICollectionView *)collectionView
layout:(UICollectionViewLayout *)collectionViewLayout
sizeForItemAtIndexPath:(NSIndexPath *)indexPath
{
CGRect screenRect = [[UIScreen mainScreen] bounds];
CGFloat screenWidth = screenRect.size.width;
float cellWidth = screenWidth / 3.0; //Replace the divisor with the column count requirement. Make sure to have it in float.
CGSize size = CGSizeMake(cellWidth, cellWidth);
return size;
}
Nob의 답변에 대한 확장:
func collectionView(collectionView: UICollectionView,
layout collectionViewLayout: UICollectionViewLayout,
sizeForItemAtIndexPath indexPath: NSIndexPath) -> CGSize {
let flowLayout = collectionViewLayout as! UICollectionViewFlowLayout
let totalSpace = flowLayout.sectionInset.left
+ flowLayout.sectionInset.right
+ (flowLayout.minimumInteritemSpacing * CGFloat(numberOfItemsPerRow - 1))
let size = Int((collectionView.bounds.width - totalSpace) / CGFloat(numberOfItemsPerRow))
return CGSize(width: size, height: size)
}
이렇게 하면 셀 사이의 모든 간격이 허용됩니다.그것은 다음을 가정합니다.Int
는 member 변수입니다.numberOfItemsPerRow
그리고 모든 세포들이 정사각형이고 크기가 같다는 것도.했듯이, 변화에도 , jhilgert00을 으로써 jhilgert00을 사용합니다.viewWillTransitionToSize
~하듯이willRotateToInterfaceOrientation
감가상각됩니다.
Swift 3 이상의 작업 코드는 두 개의 열로 구성된 레이아웃입니다.
func collectionView(_ collectionView: UICollectionView,
layout collectionViewLayout: UICollectionViewLayout,
sizeForItemAt indexPath: IndexPath) -> CGSize {
let nbCol = 2
let flowLayout = collectionViewLayout as! UICollectionViewFlowLayout
let totalSpace = flowLayout.sectionInset.left
+ flowLayout.sectionInset.right
+ (flowLayout.minimumInteritemSpacing * CGFloat(nbCol - 1))
let size = Int((collectionView.bounds.width - totalSpace) / CGFloat(nbCol))
return CGSize(width: size, height: size)
}
"nbCol"을 원하는 열 수로 자유롭게 변경할 수 있습니다.
Swift 5+ iOS 13+로 업데이트됨
집합 뷰 추정 크기는 없어야 합니다.
셀에 대한 여유 선언
let margin: CGFloat = 10
configure "DidLoad "에서minimumInteritemSpacing
,minimumLineSpacing
,sectionInset
guard let collectionView = docsColl, let flowLayout = collectionView.collectionViewLayout as? UICollectionViewFlowLayout else { return }
flowLayout.minimumInteritemSpacing = margin
flowLayout.minimumLineSpacing = margin
flowLayout.sectionInset = UIEdgeInsets(top: margin, left: margin, bottom: margin, right: margin)
UICollectionViewDataSource 메서드sizeForItemAt
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
let noOfCellsInRow = 2 //number of column you want
let flowLayout = collectionViewLayout as! UICollectionViewFlowLayout
let totalSpace = flowLayout.sectionInset.left
+ flowLayout.sectionInset.right
+ (flowLayout.minimumInteritemSpacing * CGFloat(noOfCellsInRow - 1))
let size = Int((collectionView.bounds.width - totalSpace) / CGFloat(noOfCellsInRow))
return CGSize(width: size, height: size)
}
대리인을 사용하는 것이 귀찮은 경우.
extension UICollectionView {
func setItemsInRow(items: Int) {
if let layout = self.collectionViewLayout as? UICollectionViewFlowLayout {
let contentInset = self.contentInset
let itemsInRow: CGFloat = CGFloat(items);
let innerSpace = layout.minimumInteritemSpacing * (itemsInRow - 1.0)
let insetSpace = contentInset.left + contentInset.right + layout.sectionInset.left + layout.sectionInset.right
let width = floor((CGRectGetWidth(frame) - insetSpace - innerSpace) / itemsInRow);
layout.itemSize = CGSizeMake(width, width)
}
}
}
PS: 회전 후에도 호출되어야 합니다.
Swift 3으로 업데이트됨:
흐름 레이아웃 대신 특정 열 번호와 행 번호에 대해 사용자 지정 레이아웃을 사용하는 것을 선호합니다.이유:
- 열 번호가 매우 크면 수평으로 끌 수 있습니다.
- 열과 행을 사용하기 때문에 논리적으로 더 적합합니다.
일반 셀 및 헤더 셀: (xib에 IBOutlet으로 UI 레이블 추가):
class CollectionViewCell: UICollectionViewCell {
@IBOutlet weak var label: UILabel!
override func awakeFromNib() {
super.awakeFromNib()
// Initialization code
self.backgroundColor = UIColor.black
label.textColor = UIColor.white
}
}
class CollectionViewHeadCell: UICollectionViewCell {
@IBOutlet weak var label: UILabel!
override func awakeFromNib() {
super.awakeFromNib()
// Initialization code
self.backgroundColor = UIColor.darkGray
label.textColor = UIColor.white
}
}
사용자 지정 레이아웃:
let cellHeight: CGFloat = 100
let cellWidth: CGFloat = 100
class CustomCollectionViewLayout: UICollectionViewLayout {
private var numberOfColumns: Int!
private var numberOfRows: Int!
// It is two dimension array of itemAttributes
private var itemAttributes = [[UICollectionViewLayoutAttributes]]()
// It is one dimension of itemAttributes
private var cache = [UICollectionViewLayoutAttributes]()
override func prepare() {
if self.cache.isEmpty {
self.numberOfColumns = self.collectionView?.numberOfItems(inSection: 0)
self.numberOfRows = self.collectionView?.numberOfSections
// Dynamically change cellWidth if total cell width is smaller than whole bounds
/* if (self.collectionView?.bounds.size.width)!/CGFloat(self.numberOfColumns) > cellWidth {
self.cellWidth = (self.collectionView?.bounds.size.width)!/CGFloat(self.numberOfColumns)
}
*/
for row in 0..<self.numberOfRows {
var row_temp = [UICollectionViewLayoutAttributes]()
for column in 0..<self.numberOfColumns {
let indexPath = NSIndexPath(item: column, section: row)
let attributes = UICollectionViewLayoutAttributes(forCellWith: indexPath as IndexPath)
attributes.frame = CGRect(x: cellWidth*CGFloat(column), y: cellHeight*CGFloat(row), width: cellWidth, height: cellHeight)
row_temp.append(attributes)
self.cache.append(attributes)
}
self.itemAttributes.append(row_temp)
}
}
}
override var collectionViewContentSize: CGSize {
return CGSize(width: CGFloat(self.numberOfColumns)*cellWidth, height: CGFloat(self.numberOfRows)*cellHeight)
}
override func layoutAttributesForElements(in rect: CGRect) -> [UICollectionViewLayoutAttributes]? {
var layoutAttributes = [UICollectionViewLayoutAttributes]()
for attributes in cache {
if attributes.frame.intersects(rect) {
layoutAttributes.append(attributes)
}
}
return layoutAttributes
}
}
컬렉션 보기:
let CellIdentifier = "CellIdentifier"
let HeadCellIdentifier = "HeadCellIdentifier"
class CollectionView: UICollectionView, UICollectionViewDelegate, UICollectionViewDataSource {
init() {
let layout = CustomCollectionViewLayout()
super.init(frame: CGRect.zero, collectionViewLayout: layout)
self.register(UINib(nibName: "CollectionViewCell", bundle: nil), forCellWithReuseIdentifier: CellIdentifier)
self.register(UINib(nibName: "CollectionViewHeadCell", bundle: nil), forCellWithReuseIdentifier: HeadCellIdentifier)
self.isDirectionalLockEnabled = true
self.dataSource = self
self.delegate = self
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
func updateCollectionView() {
DispatchQueue.main.async {
self.reloadData()
}
}
// MARK: CollectionView datasource
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return 20
}
func numberOfSections(in collectionView: UICollectionView) -> Int {
return 20
}
override func numberOfItems(inSection section: Int) -> Int {
return 20
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let column = (indexPath as NSIndexPath).row
let row = (indexPath as NSIndexPath).section
if column == 0 {
let cell : CollectionViewHeadCell = collectionView.dequeueReusableCell(withReuseIdentifier: HeadCellIdentifier, for: indexPath) as! CollectionViewHeadCell
cell.label.text = "\(row)"
return cell
}
else if row == 0 {
let cell : CollectionViewHeadCell = collectionView.dequeueReusableCell(withReuseIdentifier: HeadCellIdentifier, for: indexPath) as! CollectionViewHeadCell
cell.label.text = "\(column)"
return cell
}
else {
let cell : CollectionViewCell = collectionView.dequeueReusableCell(withReuseIdentifier: CellIdentifier, for: indexPath) as! CollectionViewCell
cell.label.text = String(format: "%d", arguments: [indexPath.section*indexPath.row])
return cell
}
}
// MARK: CollectionView delegate
func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
let column = (indexPath as NSIndexPath).row
let row = (indexPath as NSIndexPath).section
print("\(column) \(row)")
}
}
ViewController에서 CollectionView 사용:
class ViewController: UIViewController {
let collectionView = CollectionView()
override func viewDidLoad() {
collectionView.translatesAutoresizingMaskIntoConstraints = false
self.view.addSubview(collectionView)
self.view.backgroundColor = UIColor.red
self.view.addConstraints(NSLayoutConstraint.constraints(withVisualFormat: "H:|[collectionView]|", options: [], metrics: nil, views: ["collectionView": collectionView]))
self.view.addConstraints(NSLayoutConstraint.constraints(withVisualFormat: "V:|[collectionView]|", options: [], metrics: nil, views: ["collectionView": collectionView]))
}
override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)
collectionView.updateCollectionView()
}
}
드디어 멋진 컬렉션 뷰를 볼 수 있습니다!
ㅠㅠUICollectionView
사용하는 레이아웃 유형에 따라 열 수를 변경할 수 있는 여러 가지 방법이 있습니다.
그UICollectionViewFlowLayout
보기 크기/방향에 따라 달라지기 때문에 사용자가 작업 중인 열 수를 직접 지정하지 않습니다.변경할 수 있는 가장 쉬운 방법은 다음을 설정하는 것입니다.itemSize
및 재산minimumInteritemSpacing
/minimumLineSpacing
.
스위프트 3.0.수평 및 수직 스크롤 방향과 가변 간격 모두에 대해 작동합니다.
열 수 지정
let numberOfColumns: CGFloat = 3
를 구성합니다.flowLayout
지정된 것으로 렌더링하기 위해numberOfColumns
if let flowLayout = collectionView?.collectionViewLayout as? UICollectionViewFlowLayout {
let horizontalSpacing = flowLayout.scrollDirection == .vertical ? flowLayout.minimumInteritemSpacing : flowLayout.minimumLineSpacing
let cellWidth = (collectionView.frame.width - max(0, numberOfColumns - 1)*horizontalSpacing)/numberOfColumns
flowLayout.itemSize = CGSize(width: cellWidth, height: cellWidth)
}
이 대답은 swift 3.0을 위한 것입니다 -->
먼저 프로토콜을 준수합니다.
UICollectionViewDelegateFlowLayout
그런 다음 다음 방법을 추가합니다.
//this method is for the size of items
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
let width = collectionView.frame.width/3
let height : CGFloat = 160.0
return CGSize(width: width, height: height)
}
//these methods are to configure the spacing between items
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, insetForSectionAt section: Int) -> UIEdgeInsets {
return UIEdgeInsetsMake(0,0,0,0)
}
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, minimumInteritemSpacingForSectionAt section: Int) -> CGFloat {
return 0
}
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, minimumLineSpacingForSectionAt section: Int) -> CGFloat {
return 0
}
먼저 UICollectionViewDelegateFlowLayout을 프로토콜로 추가합니다.
그러면:
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize
{
var columnCount = 3
let width = (view.frame.width - 20) / columnCount
return CGSize(width: width, height: width)
}
그리기를 원하는 레이아웃에 대한 모든 내용입니다.UICollectionViewFlowLayout에서 상속되는 사용자 지정 클래스를 생성할 수 있습니다.현재 열을 설정하는 직접적인 방법은 없습니다.이러한 기능을 사용하려면 수동으로 수행해야 합니다.사용자 정의 흐름 레이아웃 클래스에서 이를 처리해야 합니다.
이제 어떻게 할 것인지에 대한 의문이 생길 것입니다.만약 당신이 셀 프레임을 방해하고 싶지 않다면, 당신은 조정할 수 있습니다.
collectionView:layout:minimumInteritemSpacingForSectionAtIndex:
collectionView:layout:minimumLineSpacingForSectionAtIndex:
또 다른 방법은 세포의 위치를 제공하는 것입니다.아래의 두 가지 메서드를 재정의하면 레이아웃 구성 중에 호출됩니다.
- (NSArray*)layoutAttributesForElementsInRect:(CGRect)rect
- (UICollectionViewLayoutAttributes *)layoutAttributesForItemAtIndexPath:(NSIndexPath *)path
UICollectionViewLayoutAttributes는 셀 위치, 프레임, Zindex 등을 처리하는 클래스입니다.
Immanou Petit의 대답 #2에 추가하고 싶었습니다.화면 너비에 관계없이 정확한 여백을 보장하기 위해 원하는 여백을 가진 반복 솔버와 열 수를 입력으로 사용합니다.저는 또한 그들의 최종 마진이 그들의 목표와 비교될 방향성 플래그는 다음과 같습니다.
반복 솔버는 아래에 나와 있으며 셀 폭과 마진을 반환합니다.
private func iterativeCellSpacing(targetMargins : CGFloat,
cellsPerRow : Int,
isMinTarget : Bool) -> (CGFloat, CGFloat)
{
var w : CGFloat = 0
var m : CGFloat = targetMargins
let cols : CGFloat = CGFloat(cellsPerRow)
let numMargins : CGFloat = cols + 1.0
let screenWidth : CGFloat = collectionView!.bounds.size.width
var delta = CGFloat.greatestFiniteMagnitude
while abs(delta) > 0.001
{
let totalMarginSpacing = numMargins * m
let totalCellSpacing = screenWidth - totalMarginSpacing
if (isMinTarget)
{
w = floor(totalCellSpacing / cols)
m = ceil((screenWidth - cols * w) / numMargins)
}
else
{
w = ceil(totalCellSpacing / cols)
m = floor((screenWidth - cols * w) / numMargins)
}
delta = screenWidth - w * CGFloat(cellsPerRow) - m * numMargins
}
return (w, m)
}
저는 그것을 다음과 같이 부릅니다.
fileprivate var margin: CGFloat = 20
fileprivate var cellWidth : CGFloat = 80
fileprivate let cellsPerRow = 4
override func viewDidLoad()
{
super.viewDidLoad()
(cellWidth, margin) = iterativeCellSpacing(targetMargins: margin, cellsPerRow: 4, isMinTarget: true)
...
}
그런 다음 cellWidth 및 여백 값을 다음과 같이 흐름 레이아웃에 적용합니다.
extension MyCollectionController : UICollectionViewDelegateFlowLayout
funcollectionView(_collectionView: UICollectionView, layoutcollectionViewLayout: UICollectionViewLayout, sizeForItemAtindexPath: IndexPath) -> CG 크기 {반환 CG 크기(폭: 셀 너비, 높이: 셀 너비) }
override func viewWillTransition(to size: CGSize, with coordinator: UIViewControllerTransitionCoordinator) {
collectionView?.collectionViewLayout.invalidateLayout()
super.viewWillTransition(to: size, with: coordinator)
}
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, insetForSectionAt section: Int) -> UIEdgeInsets
{
return UIEdgeInsetsMake(margin, margin, margin, margin)
}
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, minimumLineSpacingForSectionAt section: Int) -> CGFloat
{
return margin
}
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, minimumInteritemSpacingForSectionAt section: Int) -> CGFloat
{
return margin
}
}
이게 도움이 되길 바랍니다.마진이 정확한지 확인할 수 있는 더 쉬운 방법이 있을 수 있지만, 이것은 한 가지 방법입니다.또한 이 코드는 수집 보기를 회전할 수 있는 장치에 대해 테스트되지 않았습니다.
감사해요.
완벽한 솔루션은 Using UICollectionViewDelegateFlowLayout을 사용하는 것이지만 셀 너비를 쉽게 계산하고 원하는 열 수로 나눌 수 있습니다.
문제는 분수 없이 폭을 만드는 것입니다.
(UICollectionViewLayout*)collectionViewLayout sizeForItemAtIndexPath:(NSIndexPath *)indexPath
{
CGFloat screenWidth = self.view.frame.size.width;
CGFloat marginWidth = (screenWidth - collectionView.frame.size.width);
CGFloat cellWith = (collectionView.frame.size.width - marginWidth )/3;
cellWith= floorf(cellWith);
CGSize retval = CGSizeMake(cellWith,cellWith);
return retval;}
저는 컬렉션 레이아웃을 만들었습니다.
구분 기호를 표시하려면 집합 뷰의 배경색을 회색으로 설정합니다.섹션당 하나의 행입니다.
용도:
let layout = GridCollectionViewLayout()
layout.cellHeight = 50 // if not set, cellHeight = Collection.height/numberOfSections
layout.cellWidth = 50 // if not set, cellWidth = Collection.width/numberOfItems(inSection)
collectionView.collectionViewLayout = layout
레이아웃:
import UIKit
class GridCollectionViewLayout: UICollectionViewLayout {
var cellWidth : CGFloat = 0
var cellHeight : CGFloat = 0
var seperator: CGFloat = 1
private var cache = [UICollectionViewLayoutAttributes]()
override func prepare() {
guard let collectionView = self.collectionView else {
return
}
self.cache.removeAll()
let numberOfSections = collectionView.numberOfSections
if cellHeight <= 0
{
cellHeight = (collectionView.bounds.height - seperator*CGFloat(numberOfSections-1))/CGFloat(numberOfSections)
}
for section in 0..<collectionView.numberOfSections {
let numberOfItems = collectionView.numberOfItems(inSection: section)
let cellWidth2 : CGFloat
if cellWidth <= 0
{
cellWidth2 = (collectionView.bounds.width - seperator*CGFloat(numberOfItems-1))/CGFloat(numberOfItems)
}
else
{
cellWidth2 = cellWidth
}
for row in 0..<numberOfItems {
let indexPath = NSIndexPath(row: row, section: section)
let attributes = UICollectionViewLayoutAttributes(forCellWith: indexPath as IndexPath)
attributes.frame = CGRect(x: (cellWidth2+seperator)*CGFloat(row),
y: (cellHeight+seperator)*CGFloat(section),
width: cellWidth2,
height: cellHeight)
//row_temp.append(attributes)
self.cache.append(attributes)
}
//self.itemAttributes.append(row_temp)
}
}
override var collectionViewContentSize: CGSize {
guard let collectionView = collectionView else
{
return CGSize.zero
}
if (collectionView.numberOfSections <= 0)
{
return collectionView.bounds.size
}
let width:CGFloat
if cellWidth <= 0
{
width = collectionView.bounds.width
}
else
{
width = cellWidth*CGFloat(collectionView.numberOfItems(inSection: 0))
}
let numberOfSections = CGFloat(collectionView.numberOfSections)
var height:CGFloat = 0
height += numberOfSections * cellHeight
height += (numberOfSections - 1) * seperator
return CGSize(width: width, height: height)
}
override func layoutAttributesForElements(in rect: CGRect) -> [UICollectionViewLayoutAttributes]? {
var layoutAttributes = [UICollectionViewLayoutAttributes]()
for attributes in cache {
if attributes.frame.intersects(rect) {
layoutAttributes.append(attributes)
}
}
return layoutAttributes
}
override func layoutAttributesForItem(at indexPath: IndexPath) -> UICollectionViewLayoutAttributes? {
return cache[indexPath.item]
}
}
이거 해봐요, 저한테 딱 맞아요
다음 단계를 수행합니다.
.h 파일에 값을 정의합니다.
#define kNoOfColumsForCollection 3
#define kNoOfRowsForCollection 4
#define kcellSpace 5
#define kCollectionViewCellWidth (self.view.frame.size.width - kcellSpace*kNoOfColumsForCollection)/kNoOfColumsForCollection
#define kCollectionViewCellHieght (self.view.frame.size.height-40- kcellSpace*kNoOfRowsForCollection)/kNoOfRowsForCollection
OR
#define kNoOfColumsForCollection 3
#define kCollectionViewCellWidthHieght (self.view.frame.size.width - 6*kNoOfColumsForCollection)/kNoOfColumsForCollection
2. 아래와 같이 collection View Layout 데이터 소스 메서드에 Code를 추가합니다.
#pragma mark Collection View Layout data source methods
// collection view with autolayout
- (CGFloat)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout*)collectionViewLayout minimumLineSpacingForSectionAtIndex:(NSInteger)section
{
return 4;
}
- (CGFloat)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout*)collectionViewLayout minimumInteritemSpacingForSectionAtIndex:(NSInteger)section
{
return 1;
}
- (UIEdgeInsets)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout*)collectionViewLayout insetForSectionAtIndex:(NSInteger)section
{
return UIEdgeInsetsMake(4, 4, 4, 4);
}
- (CGSize)collectionView:(UICollectionView *)collectionView
layout:(UICollectionViewLayout *)collectionViewLayout
sizeForItemAtIndexPath:(NSIndexPath *)indexPath
{
return
CGSizeMake(kCollectionViewCellWidth,kCollectionViewCellHieght);
// CGSizeMake (kCollectionViewCellWidthHieght,kCollectionViewCellWidthHieght);
}
이것이 누군가에게 도움이 되기를 바랍니다.
언급URL : https://stackoverflow.com/questions/14674986/uicollectionview-set-number-of-columns
'programing' 카테고리의 다른 글
데이터 주석의 As.Net Mvc 숨겨진 필드 (0) | 2023.07.01 |
---|---|
Git 하위 모듈과의 충돌을 관리하려면 어떻게 해야 합니까? (0) | 2023.06.26 |
정적 메서드 내에서 세션 변수 값을 가져오려면 어떻게 해야 합니까? (0) | 2023.06.26 |
crt0.o와 crt1.o -- 무엇이 다릅니까? (0) | 2023.06.26 |
Github 풀 요청을 통합 diff로 다운로드합니다. (0) | 2023.06.26 |