【发布时间】:2013-03-28 14:59:52
【问题描述】:
我将在我的一个项目中创建一个书架。基本要求如下:
- 类似于 iBooks 书架
- 很好地支持两种方向
- 很好地支持各种iOS设备(不同分辨率)
- 支持删除和插入项目
- 支持通过长按手势重新排序项目
- 当第一行被拉下时显示一个隐藏的标志
UICollectionView 是我想到的第一个选项。它很容易支持网格单元。于是我google了一下,发现了一些非常有用的教程:
Bryan Hansen's UICollectionView custom layout tutorial
Mark Pospesel's How to Add a Decoration View to a UICollectionView
LXReorderableCollectionViewFlowLayout
结果如下:(请忽略颜色不一致问题,因为我选择的图形还不完美。)
我做了什么:
- 通过创建继承自 UICollectionFlowLayout 的
LXReorderableCollectionViewFlowLayout的类(用于重新排序)来创建自定义布局 - 添加了用于显示徽标的装饰视图
- 添加了展示书架的装饰视图
但我遇到了一些问题:
1.如果项目可以在一个屏幕上显示,我根本无法滚动
然后我添加了以下代码,以使 contentsize 更大
- (CGSize)collectionViewContentSize
{
return CGSizeMake(self.collectionView.bounds.size.width, self.collectionView.bounds.size.height+100);
}
那我现在可以滚动了。这里我拉下第一行:
您可以看到徽标的装饰视图正在工作。
2。但是当我拉出最后一行时,我遇到了第二组问题:
可以看到绿框部分没有添加装饰视图。
3.书架装饰视图的背景越来越暗。 (请参考same problem here
4.当我重新排序项目时,书架栏有时会移动
我在这里列出一些重要的代码:
- (void)prepareLayout
{
// call super so flow layout can do all the math for cells, headers, and footers
[super prepareLayout];
NSMutableDictionary *dictionary = [NSMutableDictionary dictionary];
NSMutableDictionary *shelfLayoutInfo = [NSMutableDictionary dictionary];
// decoration view - emblem
NSIndexPath *indexPath = [NSIndexPath indexPathForItem:0 inSection:0];
UICollectionViewLayoutAttributes *emblemAttributes =
[UICollectionViewLayoutAttributes layoutAttributesForDecorationViewOfKind:[EmblemView kind]
withIndexPath:indexPath];
emblemAttributes.frame = [self frameForEmblem:YES];
dictionary[[EmblemView kind]] = @{indexPath: emblemAttributes};
// Calculate where shelves go in a vertical layout
int sectionCount = [self.collectionView numberOfSections];
CGFloat y = 0;
CGFloat availableWidth = self.collectionViewContentSize.width - (self.sectionInset.left + self.sectionInset.right);
int itemsAcross = floorf((availableWidth + self.minimumInteritemSpacing) / (self.itemSize.width + self.minimumInteritemSpacing));
for (int section = 0; section < sectionCount; section++)
{
y += self.headerReferenceSize.height;
//y += self.sectionInset.top;
int itemCount = [self.collectionView numberOfItemsInSection:section];
int rows = ceilf(itemCount/(float)itemsAcross)+1; // add 2 more empty row which doesn't have any data
for (int row = 0; row < rows; row++)
{
indexPath = [NSIndexPath indexPathForItem:row inSection:section];
shelfLayoutInfo[indexPath] = [NSValue valueWithCGRect:CGRectMake(0,y, self.collectionViewContentSize.width, self.itemSize.height + DECORATION_HEIGHT)];
y += self.itemSize.height;
if (row < rows - 1)
y += self.minimumLineSpacing;
}
y += self.sectionInset.bottom;
y += self.footerReferenceSize.height;
}
dictionary[[ShelfView kind]] = shelfLayoutInfo;
self.shelfLayoutInfo = dictionary;
}
- (NSArray *)layoutAttributesForElementsInRect:(CGRect)rect
{
NSArray *attributesArrayInRect = [super layoutAttributesForElementsInRect:rect];
// cell layout info
for (BookShelfLayoutAttributes *attribs in attributesArrayInRect)
{
attribs.zIndex = 1;
CATransform3D t = CATransform3DIdentity;
t = CATransform3DTranslate(t, 0, 0, 40);
attribs.transform3D = CATransform3DRotate(t, 15 * M_PI / 180, 1, 0, 0);
}
// Add our decoration views (shelves)
NSMutableDictionary* shelfDictionary = self.shelfLayoutInfo[[ShelfView kind]];
NSMutableArray *newArray = [attributesArrayInRect mutableCopy];
[shelfDictionary enumerateKeysAndObjectsUsingBlock:^(id key, NSValue* obj, BOOL *stop) {
if (CGRectIntersectsRect([obj CGRectValue], rect))
{
UICollectionViewLayoutAttributes *attributes = [UICollectionViewLayoutAttributes layoutAttributesForDecorationViewOfKind:[ShelfView kind] withIndexPath:key];
attributes.frame = [obj CGRectValue];
NSLog(@"decorationView rect = %@",NSStringFromCGRect(attributes.frame));
attributes.zIndex = 0;
//attributes.alpha = 0.5; // screenshots
[newArray addObject:attributes];
}
}];
attributesArrayInRect = [NSArray arrayWithArray:newArray];
NSMutableDictionary* emblemDictionary = self.shelfLayoutInfo[[EmblemView kind]];
NSMutableArray *newArray2 = [attributesArrayInRect mutableCopy];
[emblemDictionary enumerateKeysAndObjectsUsingBlock:^(NSIndexPath *indexPath, UICollectionViewLayoutAttributes *attributes, BOOL *innerStop) {
if (CGRectIntersectsRect(rect, attributes.frame)) {
[newArray2 addObject:attributes];
}
}];
attributesArrayInRect = [NSArray arrayWithArray:newArray2];
return attributesArrayInRect;
}
如果您有足够的耐心阅读这篇文章并提供任何建议或建议,我们将不胜感激。如果我能解决所有问题,我会发布完整的源代码。提前谢谢你。
【问题讨论】:
-
我在 Apple 的论坛中找到了一个帖子。看来装饰视图的重复是一个错误。 devforums.apple.com/message/773776#773776
-
你应该真正计算你的集合视图的内容大小作为你的 prepareLayout 函数的一部分。就目前而言,无论集合视图中有多少项目,您都只能向下滚动 100 像素。
-
如果您在问题标题中包含“UICollectionView”所属的语言或库,这可能有助于获得答案。不明显。
标签: ios6 uicollectionview uicollectionviewlayout