为什么在将 UICollectionViewLayout 分配给 UICollectionView 后,UICollectionViewCells 不再可见?
Why are UICollectionViewCells no longer visibile after assigning a UICollectionViewLayout to the UICollectionView?
我的应用有一个 UIViewController
class;在这个 class 中,我连接了一个从 Storyboard 加载的 UICollectionView
。
我正在使用 UICollectionViewLayout
class 创建自定义布局。这是它的样子:
class MyLayout: UICollectionViewLayout {
override func prepareLayout() {
super.prepareLayout()
}
override func collectionViewContentSize() -> CGSize {
let attributes = super.collectionViewContentSize()
return attributes
}
override func layoutAttributesForElementsInRect(rect: CGRect) -> [AnyObject]? {
let attributes = super.layoutAttributesForElementsInRect(rect) as? [UICollectionViewLayoutAttributes]
return attributes
}
override func layoutAttributesForItemAtIndexPath(indexPath:
NSIndexPath) -> UICollectionViewLayoutAttributes {
let attributes = super.layoutAttributesForItemAtIndexPath(indexPath)
return attributes
}
}
要将 UICollectionViewLayout
分配给 UICollectionView
,我使用 UICollectionView
的 collectionViewLayout
属性:
myCollectionView.collectionViewLayout = MyLayout()
运行 应用程序,UICollectionViewCells
不再可见。不过,它们在分配 UICollectionViewLayout
之前是可见的。我现在只能看到 UICollectionView
.
的背景
为什么单元格不再可见?
更新
我仔细查看了 UICollectionView
的 UICollectionViewLayoutAttributes
,尤其是 contentSize
。我把它的值打印出来,好像等于(0.0, 0.0)
。 layoutAttributesForElementsInRect
的 attributes
值也等于 nil
。绝对是一个危险信号。
Download the project
我认为你可以让几乎所有的东西都完全一样。将自定义布局的 class 类型更改为 UICollectionViewFlowLayout
。
class myLayout: UICollectionViewFlowLayout {
//all your code here
}
此外,将 myLayout 更改为 MyLayout 以取得良好效果:)
首先,您应该使用布局初始化 UICollectionView,而不是事后设置它:
var collectionView = UICollectionView(frame: frame, collectionViewLayout: myLayout)
You normally specify a layout object when creating a collection view [...]
下一步,如果你子class UICollectionViewLayout
,你必须实现collectionViewContentSize
和return一个你自己的值.在这里调用 super 是未定义的,除非你是 subclassing UICollectionViewFlowLayout
。
Subclasses must override this method and use it to return the width and height of the collection view’s content. These values represent the width and height of all the content, not just the content that is currently visible. The collection view uses this information to configure its own content size for scrolling purposes.
那是因为 UICollectionViewLayout 本身是一个抽象class,什么都不做(它应该被子class编辑)。
The UICollectionViewLayout class is an abstract base class that you subclass and use to generate layout information for a collection view.
同理,你还需要在layoutAttributesForElementsInRect:
中计算你自己的layoutAttributes。最简单的方法是在 prepareLayout
方法中计算所有你需要的布局,然后只得到你需要的那些。这是自定义布局的"core":
- 向委托人询问您必须在 collectionView 中显示的元素数量。
- 对于每个元素,首先创建正确的 indexPath,然后使用
UICollectionViewLayoutAttributes(forCellWithIndexPath: indexPath)
. 为该 indexPath 创建一个空的 layoutAttribute
- 计算并设置该布局属性的
frame
属性。
- 将该 layoutAttribute 存储在声明为 MutableArray 的私有 属性 中。
- 在
layoutAttributesForElementsInRect:
中,遍历您之前实例化的所有存储的 layoutAttributes,以及 return 其 frame
与提供的 rect
相交的子集。 UICollectionView 将要求其数据源为每个 layoutAttributes 提供一个单元格 return 通过该方法(通过 cellForItemAtIndexPath
)编辑,以及那些 frame
将使用这些布局属性中的 frame
属性 设置单元格。
如果你能阅读 Objective-C 和 Swift,你可以看看 my sample UICollectionViewLayout
implementation here, which makes the UICollectionView mimic the daily view of the iOS calendar app (screenshot)。
如果您的目标是实现相当标准的布局(即放置在水平或垂直流动的网格中的元素),我建议您从 subclassing UICollectionViewFlowLayout
相反,因为它已经是 UICollectionViewLayout
的有效实现,这意味着您可以在大多数方法中使用 super
来获取默认值。
此外,关于如何创建您自己的自定义布局的好书 here in the official documentation。
我的应用有一个 UIViewController
class;在这个 class 中,我连接了一个从 Storyboard 加载的 UICollectionView
。
我正在使用 UICollectionViewLayout
class 创建自定义布局。这是它的样子:
class MyLayout: UICollectionViewLayout {
override func prepareLayout() {
super.prepareLayout()
}
override func collectionViewContentSize() -> CGSize {
let attributes = super.collectionViewContentSize()
return attributes
}
override func layoutAttributesForElementsInRect(rect: CGRect) -> [AnyObject]? {
let attributes = super.layoutAttributesForElementsInRect(rect) as? [UICollectionViewLayoutAttributes]
return attributes
}
override func layoutAttributesForItemAtIndexPath(indexPath:
NSIndexPath) -> UICollectionViewLayoutAttributes {
let attributes = super.layoutAttributesForItemAtIndexPath(indexPath)
return attributes
}
}
要将 UICollectionViewLayout
分配给 UICollectionView
,我使用 UICollectionView
的 collectionViewLayout
属性:
myCollectionView.collectionViewLayout = MyLayout()
运行 应用程序,UICollectionViewCells
不再可见。不过,它们在分配 UICollectionViewLayout
之前是可见的。我现在只能看到 UICollectionView
.
为什么单元格不再可见?
更新
我仔细查看了 UICollectionView
的 UICollectionViewLayoutAttributes
,尤其是 contentSize
。我把它的值打印出来,好像等于(0.0, 0.0)
。 layoutAttributesForElementsInRect
的 attributes
值也等于 nil
。绝对是一个危险信号。
Download the project
我认为你可以让几乎所有的东西都完全一样。将自定义布局的 class 类型更改为 UICollectionViewFlowLayout
。
class myLayout: UICollectionViewFlowLayout {
//all your code here
}
此外,将 myLayout 更改为 MyLayout 以取得良好效果:)
首先,您应该使用布局初始化 UICollectionView,而不是事后设置它:
var collectionView = UICollectionView(frame: frame, collectionViewLayout: myLayout)
You normally specify a layout object when creating a collection view [...]
下一步,如果你子class UICollectionViewLayout
,你必须实现collectionViewContentSize
和return一个你自己的值.在这里调用 super 是未定义的,除非你是 subclassing UICollectionViewFlowLayout
。
Subclasses must override this method and use it to return the width and height of the collection view’s content. These values represent the width and height of all the content, not just the content that is currently visible. The collection view uses this information to configure its own content size for scrolling purposes.
那是因为 UICollectionViewLayout 本身是一个抽象class,什么都不做(它应该被子class编辑)。
The UICollectionViewLayout class is an abstract base class that you subclass and use to generate layout information for a collection view.
同理,你还需要在layoutAttributesForElementsInRect:
中计算你自己的layoutAttributes。最简单的方法是在 prepareLayout
方法中计算所有你需要的布局,然后只得到你需要的那些。这是自定义布局的"core":
- 向委托人询问您必须在 collectionView 中显示的元素数量。
- 对于每个元素,首先创建正确的 indexPath,然后使用
UICollectionViewLayoutAttributes(forCellWithIndexPath: indexPath)
. 为该 indexPath 创建一个空的 layoutAttribute
- 计算并设置该布局属性的
frame
属性。 - 将该 layoutAttribute 存储在声明为 MutableArray 的私有 属性 中。
- 在
layoutAttributesForElementsInRect:
中,遍历您之前实例化的所有存储的 layoutAttributes,以及 return 其frame
与提供的rect
相交的子集。 UICollectionView 将要求其数据源为每个 layoutAttributes 提供一个单元格 return 通过该方法(通过cellForItemAtIndexPath
)编辑,以及那些frame
将使用这些布局属性中的frame
属性 设置单元格。
如果你能阅读 Objective-C 和 Swift,你可以看看 my sample UICollectionViewLayout
implementation here, which makes the UICollectionView mimic the daily view of the iOS calendar app (screenshot)。
如果您的目标是实现相当标准的布局(即放置在水平或垂直流动的网格中的元素),我建议您从 subclassing UICollectionViewFlowLayout
相反,因为它已经是 UICollectionViewLayout
的有效实现,这意味着您可以在大多数方法中使用 super
来获取默认值。
此外,关于如何创建您自己的自定义布局的好书 here in the official documentation。