UICollectionView 单元格不占用 UICollectionView 的宽度
UICollectionView cells do not take up width of UICollectionView
UICollectionView 宽度会因设备而异,因为它被限制为达到视图的水平边距。 collectionView 的布局是 Flow。我使用 UICollectionView 的唯一原因是 space 图像在不同尺寸的设备上均匀分布,并且所有这些图像都将具有点击手势识别器。行数是可变的,因为图像图标的数量会有所不同。显然这是我追求的方法:
func collectionView(collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAtIndexPath indexPath: NSIndexPath) -> CGSize {
return CGSize(width: collectionViewWidth/6, height: collectionViewWidth/6);
}
我试过这样做:
var collectionViewWidth: CGFloat = 0.0
override func viewDidLoad() {
super.viewDidLoad()
collectionView.dataSource = self
}
override func viewDidAppear(animated: Bool) {
collectionViewWidth = collectionView.collectionViewLayout
.collectionViewContentSize().width
}
func collectionView(collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAtIndexPath indexPath: NSIndexPath) -> CGSize {
return CGSize(width: collectionViewWidth/6, height: collectionViewWidth/6);
}
但是我在代码中尝试的任何事情都不会对最终输出产生任何影响,这就是最终输出(忘记不在 UICollectionView 中的图像 - 它们将被删除):
我在界面生成器中更改了单元格的大小,结果是这样的:
所以我有两个问题:
为什么上图中的单元格没有走到UICollectionView的边缘?
如何在 运行 时以编程方式设置单元格大小,使我的 UICollectionView 在所有设备尺寸上都有 6 列?
这是我的 ViewController 的所有代码,其中包含 UICollectionView:
import UIKit
class DressingRoomViewController: UIViewController {
@IBOutlet weak var collectionView: UICollectionView!
let identifier = "cellIdentifier"
let dataSource = DataSource()
var collectionViewWidth: CGFloat = 0.0
override func viewDidLoad() {
super.viewDidLoad()
collectionView.dataSource = self
}
override func viewDidAppear(animated: Bool) {
collectionViewWidth = collectionView.collectionViewLayout
.collectionViewContentSize().width
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
override func prepareForSegue( segue: UIStoryboardSegue,
sender: AnyObject?) {
if (segue.identifier == "dressingRoom2MyOutfits") {
let myOutfitsViewController = segue.destinationViewController
as! MyOutfitsViewController
}
}
}
// MARK:- UICollectionViewDataSource Delegate
extension DressingRoomViewController : UICollectionViewDataSource {
func numberOfSectionsInCollectionView(
collectionView: UICollectionView) -> Int {
return dataSource.groups.count
}
func collectionView(collectionView: UICollectionView,
numberOfItemsInSection section: Int) -> Int {
return dataSource.numbeOfRowsInEachGroup(section)
}
func collectionView(collectionView: UICollectionView,
cellForItemAtIndexPath indexPath: NSIndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCellWithReuseIdentifier(
identifier,forIndexPath:indexPath) as! FruitCell
let fruits: [Fruit] = dataSource.fruitsInGroup(indexPath.section)
let fruit = fruits[indexPath.row]
let name = fruit.name!
cell.imageView.image = UIImage(named: name)
cell.caption.text = name.capitalizedString
return cell
}
func collectionView(collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAtIndexPath indexPath: NSIndexPath) -> CGSize {
return CGSize(width: collectionViewWidth/6, height: collectionViewWidth/6);
}
}
可能值得一提的是,我的 UICollectionView 数据源被分组只是因为我正在做一个教程。这是数据源代码:
class数据源{
init() {
populateData()
}
var fruits:[Fruit] = []
var groups:[String] = []
func numbeOfRowsInEachGroup(index: Int) -> Int {
return fruitsInGroup(index).count
}
func numberOfGroups() -> Int {
return groups.count
}
func gettGroupLabelAtIndex(index: Int) -> String {
return groups[index]
}
// MARK:- Populate Data from plist
func populateData() {
if let path = NSBundle.mainBundle().pathForResource(
"Fruits", ofType: "plist") {
if let dictArray = NSArray(contentsOfFile: path) {
for item in dictArray {
if let dict = item as? NSDictionary {
let name = dict["name"] as! String
let group = dict["group"] as! String
let fruit = Fruit(name: name, group: group)
if !contains(groups, group){
groups.append(group)
}
fruits.append(fruit)
}
}
}
}
}
// MARK:- FruitsForEachGroup
func fruitsInGroup(index: Int) -> [Fruit] {
let item = groups[index]
let filteredFruits = fruits.filter { (fruit: Fruit) -> Bool in
return fruit.group == item
}
return filteredFruits
}
}
这是加载到数据源中的 plist:
编辑:我做了一些工作来删除不需要的组。我看到这些组导致新行开始得太早。我将代码更改为:
// MARK:- UICollectionViewDataSource Delegate
extension DressingRoomViewController : UICollectionViewDataSource {
func numberOfSectionsInCollectionView(
collectionView: UICollectionView) -> Int {
return 1
}
func collectionView(collectionView: UICollectionView,
numberOfItemsInSection section: Int) -> Int {
return 12
}
func collectionView(collectionView: UICollectionView,
cellForItemAtIndexPath indexPath: NSIndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCellWithReuseIdentifier(
identifier,forIndexPath:indexPath) as! FruitCell
let fruits: [Fruit] = dataSource.fruits
let fruit = fruits[indexPath.row]
let name = fruit.name!
cell.imageView.image = UIImage(named: name)
cell.caption.text = name.capitalizedString
return cell
}
func collectionView(collectionView: UICollectionView,
sizeForItemAtIndexPath indexPath: NSIndexPath) -> CGSize {
return CGSize(width: 200, height: 200);
}
}
现在我只需要以某种方式使单元格宽度成为集合视图宽度的 1/6,然后剪掉刚刚浪费的 UICollectioview 底部 space
对于布局,我们基本上更喜欢创建一个 CustomflowLayout,继承自 UICollectionViewFlowlayout 并覆盖它的 2 个方法:
- layoutAttributesForElementsInRect:(必需)
- layoutAttributesForItemAtIndexPath:(必需)
然后设置
[self.collectionview setFlowlayout:CustomflowLayout];
如果您使用的是 UICollectionViewFlowLayout,则配置单元格宽度的方式是与 UICollectionViewFlowLayout 对话。设置其 itemSize
.
您可以在viewDidLoad中设置collectionViewLayout的itemSize,如本例所示:
override func viewDidLoad() {
super.viewDidLoad()
let layout = collectionView.collectionViewLayout as! UICollectionViewFlowLayout
let collectionViewSize = collectionView.frame.size
let nrOfCellsPerRow = 6
let itemWidth = collectionViewSize.width/nrOfCellsPerRow
let itemHeight = 80 // example
layout.itemSize = CGSize(width: itemWidth, height: itemHeight)
}
如果您希望单元格之间有间距,则必须补偿 itemWidth 计算
UICollectionView 宽度会因设备而异,因为它被限制为达到视图的水平边距。 collectionView 的布局是 Flow。我使用 UICollectionView 的唯一原因是 space 图像在不同尺寸的设备上均匀分布,并且所有这些图像都将具有点击手势识别器。行数是可变的,因为图像图标的数量会有所不同。显然这是我追求的方法:
func collectionView(collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAtIndexPath indexPath: NSIndexPath) -> CGSize {
return CGSize(width: collectionViewWidth/6, height: collectionViewWidth/6);
}
我试过这样做:
var collectionViewWidth: CGFloat = 0.0
override func viewDidLoad() {
super.viewDidLoad()
collectionView.dataSource = self
}
override func viewDidAppear(animated: Bool) {
collectionViewWidth = collectionView.collectionViewLayout
.collectionViewContentSize().width
}
func collectionView(collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAtIndexPath indexPath: NSIndexPath) -> CGSize {
return CGSize(width: collectionViewWidth/6, height: collectionViewWidth/6);
}
但是我在代码中尝试的任何事情都不会对最终输出产生任何影响,这就是最终输出(忘记不在 UICollectionView 中的图像 - 它们将被删除):
我在界面生成器中更改了单元格的大小,结果是这样的:
所以我有两个问题:
为什么上图中的单元格没有走到UICollectionView的边缘?
如何在 运行 时以编程方式设置单元格大小,使我的 UICollectionView 在所有设备尺寸上都有 6 列?
这是我的 ViewController 的所有代码,其中包含 UICollectionView:
import UIKit
class DressingRoomViewController: UIViewController {
@IBOutlet weak var collectionView: UICollectionView!
let identifier = "cellIdentifier"
let dataSource = DataSource()
var collectionViewWidth: CGFloat = 0.0
override func viewDidLoad() {
super.viewDidLoad()
collectionView.dataSource = self
}
override func viewDidAppear(animated: Bool) {
collectionViewWidth = collectionView.collectionViewLayout
.collectionViewContentSize().width
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
override func prepareForSegue( segue: UIStoryboardSegue,
sender: AnyObject?) {
if (segue.identifier == "dressingRoom2MyOutfits") {
let myOutfitsViewController = segue.destinationViewController
as! MyOutfitsViewController
}
}
}
// MARK:- UICollectionViewDataSource Delegate
extension DressingRoomViewController : UICollectionViewDataSource {
func numberOfSectionsInCollectionView(
collectionView: UICollectionView) -> Int {
return dataSource.groups.count
}
func collectionView(collectionView: UICollectionView,
numberOfItemsInSection section: Int) -> Int {
return dataSource.numbeOfRowsInEachGroup(section)
}
func collectionView(collectionView: UICollectionView,
cellForItemAtIndexPath indexPath: NSIndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCellWithReuseIdentifier(
identifier,forIndexPath:indexPath) as! FruitCell
let fruits: [Fruit] = dataSource.fruitsInGroup(indexPath.section)
let fruit = fruits[indexPath.row]
let name = fruit.name!
cell.imageView.image = UIImage(named: name)
cell.caption.text = name.capitalizedString
return cell
}
func collectionView(collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAtIndexPath indexPath: NSIndexPath) -> CGSize {
return CGSize(width: collectionViewWidth/6, height: collectionViewWidth/6);
}
}
可能值得一提的是,我的 UICollectionView 数据源被分组只是因为我正在做一个教程。这是数据源代码:
class数据源{
init() {
populateData()
}
var fruits:[Fruit] = []
var groups:[String] = []
func numbeOfRowsInEachGroup(index: Int) -> Int {
return fruitsInGroup(index).count
}
func numberOfGroups() -> Int {
return groups.count
}
func gettGroupLabelAtIndex(index: Int) -> String {
return groups[index]
}
// MARK:- Populate Data from plist
func populateData() {
if let path = NSBundle.mainBundle().pathForResource(
"Fruits", ofType: "plist") {
if let dictArray = NSArray(contentsOfFile: path) {
for item in dictArray {
if let dict = item as? NSDictionary {
let name = dict["name"] as! String
let group = dict["group"] as! String
let fruit = Fruit(name: name, group: group)
if !contains(groups, group){
groups.append(group)
}
fruits.append(fruit)
}
}
}
}
}
// MARK:- FruitsForEachGroup
func fruitsInGroup(index: Int) -> [Fruit] {
let item = groups[index]
let filteredFruits = fruits.filter { (fruit: Fruit) -> Bool in
return fruit.group == item
}
return filteredFruits
}
}
这是加载到数据源中的 plist:
编辑:我做了一些工作来删除不需要的组。我看到这些组导致新行开始得太早。我将代码更改为:
// MARK:- UICollectionViewDataSource Delegate
extension DressingRoomViewController : UICollectionViewDataSource {
func numberOfSectionsInCollectionView(
collectionView: UICollectionView) -> Int {
return 1
}
func collectionView(collectionView: UICollectionView,
numberOfItemsInSection section: Int) -> Int {
return 12
}
func collectionView(collectionView: UICollectionView,
cellForItemAtIndexPath indexPath: NSIndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCellWithReuseIdentifier(
identifier,forIndexPath:indexPath) as! FruitCell
let fruits: [Fruit] = dataSource.fruits
let fruit = fruits[indexPath.row]
let name = fruit.name!
cell.imageView.image = UIImage(named: name)
cell.caption.text = name.capitalizedString
return cell
}
func collectionView(collectionView: UICollectionView,
sizeForItemAtIndexPath indexPath: NSIndexPath) -> CGSize {
return CGSize(width: 200, height: 200);
}
}
现在我只需要以某种方式使单元格宽度成为集合视图宽度的 1/6,然后剪掉刚刚浪费的 UICollectioview 底部 space
对于布局,我们基本上更喜欢创建一个 CustomflowLayout,继承自 UICollectionViewFlowlayout 并覆盖它的 2 个方法:
- layoutAttributesForElementsInRect:(必需)
- layoutAttributesForItemAtIndexPath:(必需)
然后设置
[self.collectionview setFlowlayout:CustomflowLayout];
如果您使用的是 UICollectionViewFlowLayout,则配置单元格宽度的方式是与 UICollectionViewFlowLayout 对话。设置其 itemSize
.
您可以在viewDidLoad中设置collectionViewLayout的itemSize,如本例所示:
override func viewDidLoad() {
super.viewDidLoad()
let layout = collectionView.collectionViewLayout as! UICollectionViewFlowLayout
let collectionViewSize = collectionView.frame.size
let nrOfCellsPerRow = 6
let itemWidth = collectionViewSize.width/nrOfCellsPerRow
let itemHeight = 80 // example
layout.itemSize = CGSize(width: itemWidth, height: itemHeight)
}
如果您希望单元格之间有间距,则必须补偿 itemWidth 计算