我正在尝试修改UICollectionViewFlowLayout
(垂直滚动),以便将每个部分标题放在该部分的所有项目的左侧(而不是顶部,这是默认设置)。
也就是说,这是默认行为:
......这就是我想要的:
所以我将UICollectionViewFlowLayout
override func layoutAttributesForElementsInRect(rect: CGRect) -> [UICollectionViewLayoutAttributes]? {
guard let attributesToReturn = super.layoutAttributesForElementsInRect(rect) else {
return nil
}
// Copy to avoid the dreadded "Cached frame mismatch" runtime warning:
var copiedAttributes = [UICollectionViewLayoutAttributes]()
for attribute in attributesToReturn {
copiedAttributes.append(attribute.copy() as! UICollectionViewLayoutAttributes)
}
for attributes in copiedAttributes {
if let kind = attributes.representedElementKind {
// Non nil: It is a supplementary View
if kind == UICollectionElementKindSectionHeader {
// HEADER
var frame = attributes.frame
frame.origin.y = frame.origin.y + frame.size.height
frame.size.width = sectionInset.left
attributes.frame = frame
}
}
else{
// Nil: It is an item
}
}
return copiedAttributes
}
另外,为了更好的衡量(?),我采用了协议UICollectionViewDelegateFlowLayout
并实现了这个方法(虽然不清楚什么是优先的。然后,故事板文件中有设置,但那些似乎被运行时对应物覆盖了):
func collectionView(
collectionView: UICollectionView,
layout collectionViewLayout: UICollectionViewLayout,
referenceSizeForHeaderInSection section: Int) -> CGSize {
let left = (collectionViewLayout as! UICollectionViewFlowLayout).sectionInset.left
return CGSizeMake(left, 1)
}
...我成功地将标题降低到其部分的第一行;但是,标题最初占用的空间保持打开状态:
...我唯一能做到的就是将标题视图高度设置为1
和"剪辑子视图"为false,以便显示标签(如果我将高度设置为0,则不会绘制标签),但这绝对是不最优雅的解决方案(并且可能会中断 -say- iOS 9.2 )
也就是说,标题的实际高度链接到各个部分之间的垂直空间:我不能将空间设置为零,同时将标题视图保持在合理的大小以便显示。
也许我也应该移动所有部分项目(与我的标题高度相同),以填补空洞?
答案 0 :(得分:1)
好的,这就是我所做的:
首先,我基于this github project对UICollectionViewFlowLayout
进行了子类化,以获得我正在寻找的左对齐(我必须将它从Objective-C转换为swift,但除了它的漂亮之外几乎相同)。
由于我已经是布局对象的子类,我可以在这个子类中实现任何修改。
我声明了一个属性来存储我的“side-headers”的宽度(这个数量也是每个部分左边插入的两倍):
import UIKit
class LeftAlignedFlowLayout: UICollectionViewFlowLayout
{
let customHeaderWidth:CGFloat = 150.0
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
sectionInset.left = customHeaderWidth
}
然后,在layoutAttributesForElementsInRect()
的实现中,我做到了这一点:
override func layoutAttributesForElementsInRect(rect: CGRect) -> [UICollectionViewLayoutAttributes]?
{
guard let attributesToReturn = super.layoutAttributesForElementsInRect(rect) else {
return nil
}
var copiedAttributes = [UICollectionViewLayoutAttributes]()
for attribute in attributesToReturn {
// Must copy attributes to avoid runtime warning:
copiedAttributes.append(attribute.copy() as! UICollectionViewLayoutAttributes)
}
for attributes in copiedAttributes {
if let kind = attributes.representedElementKind {
// Non nil : Supplementary View
if kind == UICollectionElementKindSectionHeader {
// [A] HEADER
var frame = attributes.frame
frame.origin.y = frame.origin.y + frame.size.height
frame.size.width = sectionInset.left
frame.size.height = 60 // Hard-coded - header height
attributes.frame = frame
}
else if kind == UICollectionElementKindSectionFooter {
// [B] FOOTER
var frame = attributes.frame
// My footer view is a "hairline" taking most of the width
// (save for 8 points of inset margin on each side):
frame.origin.x += 8
frame.size.width -= 16
attributes.frame = frame
}
}
else{
// Kind is nil : Item (cell)
if let attributesForItem = self.layoutAttributesForItemAtIndexPath(attributes.indexPath){
attributes.frame = attributesForItem.frame
}
}
}
return copiedAttributes
}
还有layoutAttributesForItemAtIndexPath()
的实现,但这更多地与items-part的左对齐有关,所以我省略了它(如果有人有兴趣,请检查上面链接的github项目)。
我会尽快创建一个包含我的实施演示项目的存储库。
这些是集合视图和流布局对象的大小检查器设置:
(顺便说一句,项目大小是可变的,并且在运行时由委托方法确定,因此请忽略这些值)
我还采用了UICollectionViewDelegateFlowLayout
协议,如下所示:
func collectionView(collectionView: UICollectionView,
layout collectionViewLayout: UICollectionViewLayout,
referenceSizeForHeaderInSection section: Int) -> CGSize
{
let left = (collectionViewLayout as! UICollectionViewFlowLayout).sectionInset.left
return CGSizeMake(left, 1)
}
虽然,老实说,一些布局属性可以在很多地方指定(Interface Builder,布局对象的属性,委托方法的返回值等等),我不记得究竟哪个取得优先权在每种情况下,我需要稍微清理一下我的代码。
答案 1 :(得分:1)
- (NSArray<UICollectionViewLayoutAttributes *> *)layoutAttributesForElementsInRect:(CGRect)rect
{
NSArray *originalAttributes = [super layoutAttributesForElementsInRect:rect];
NSMutableArray *allAttributes = [NSMutableArray new];
for (UICollectionViewLayoutAttributes* attributes in originalAttributes) {
[allAttributes addObject:[attributes copy]];
}
for (UICollectionViewLayoutAttributes *attributes in allAttributes) {
NSString *kind = attributes.representedElementKind;
if (kind == UICollectionElementKindSectionHeader) {
CGRect frame = attributes.frame;
UICollectionViewLayoutAttributes *cellAttrs = [super layoutAttributesForItemAtIndexPath:attributes.indexPath];
frame.origin.x = frame.origin.x;
frame.size.height = self.sectionInset.top;
frame.size.width = cellAttrs.frame.size.width;
attributes.frame = frame;
}
}
return allAttributes;
}