Могу ли я иметь UICollectionViewFlowLayout с scrollDirection, отличным от направления макета?
UICollectionViewFlowLayout великолепен, однако я хочу немного подправить его, чтобы scrollDirection отличалось от направления макета. Примерами того, что я хотел бы, является домашний экран трамплина или клавиатуры эмодзи, где вы можете проводить пальцем влево / вправо, но ячейки располагаются слева направо, сверху вниз (вместо сверху вниз, слева направо, как они есть). с UICollectionViewFlowLayout с scrollDirection, установленным в горизонтальное положение). Кто-нибудь знает, как я могу легко создать подкласс FlowLayout, чтобы внести это изменение? Я разочарован, что у них нет layoutDirection в дополнение к scrollDirection для объекта UICollectionViewFlowLayout:(
@ rdelmar Я реализовал нечто похожее на ваше решение, и это работает (не так элегантно, как хотелось бы), но я заметил, что иногда предметы исчезают из коллекции, если их не перерисовывать, поэтому я не принял ответ. Вот что я закончил:
@interface UICollectionViewPagedFlowLayout : UICollectionViewFlowLayout
@property int width;
@property int height;
@end
@implementation UICollectionViewPagedFlowLayout
#warning MINOR BUG: sometimes symbols disappear
- (CGSize)collectionViewContentSize {
CGSize size = [super collectionViewContentSize];
// make sure it's wide enough to cover all the objects
size.width = self.collectionView.bounds.size.width * [self.collectionView numberOfSections];
return size;
}
- (NSArray*) layoutAttributesForElementsInRect:(CGRect)rect {
NSArray *array = [super layoutAttributesForElementsInRect:rect];
CGRect visibleRect;
visibleRect.origin = self.collectionView.contentOffset;
visibleRect.size = self.collectionView.bounds.size;
for (UICollectionViewLayoutAttributes* attributes in array) {
if (CGRectIntersectsRect(attributes.frame, rect)) {
// see which section this is in
CGRect configurableRect = UIEdgeInsetsInsetRect(visibleRect, self.sectionInset);
int horizontalIndex = attributes.indexPath.row % self.width;
int verticalIndex = attributes.indexPath.row / self.width;
double xspace = (configurableRect.size.width - self.width * self.itemSize.width) / self.width;
double yspace = (configurableRect.size.height - self.height * self.itemSize.height) / self.height;
attributes.center = CGPointMake(attributes.indexPath.section * visibleRect.size.width + self.sectionInset.left + (self.itemSize.width + xspace) * horizontalIndex + self.itemSize.width / 2, self.sectionInset.top + (self.itemSize.height + yspace) * verticalIndex + self.itemSize.height / 2);
}
}
return array;
}
@end
3 ответа
IIRC, именно это демонстрируется на сессиях WWDC 2012 на UICollectionView.
Я не знаю, легко, зависит от вашего определения, я думаю. Я сделал проект, в котором у меня был макет, близкий к тому, что вы ищете. Это размещает ряды горизонтально, слева направо, сверху вниз. Моим источником данных был массив массивов, где каждый подмассив предоставлял данные для одной строки.
#import "SimpleHorizontalLayout.h" // subclass of UICollectionViewFlowLayout
#define kItemSize 60
@implementation SimpleHorizontalLayout
-(CGSize)collectionViewContentSize {
NSInteger xSize = [self.collectionView numberOfItemsInSection:0] * (kItemSize + 20); // the 20 is for spacing between cells.
NSInteger ySize = [self.collectionView numberOfSections] * (kItemSize + 20);
return CGSizeMake(xSize, ySize);
}
- (UICollectionViewLayoutAttributes *)layoutAttributesForItemAtIndexPath:(NSIndexPath *)path {
UICollectionViewLayoutAttributes* attributes = [UICollectionViewLayoutAttributes layoutAttributesForCellWithIndexPath:path];
attributes.size = CGSizeMake(kItemSize,kItemSize);
NSInteger xValue = kItemSize/2 + path.row * (kItemSize +20) ;
NSInteger yValue = kItemSize + path.section * (kItemSize +20);
attributes.center = CGPointMake(xValue, yValue);
return attributes;
}
-(NSArray*)layoutAttributesForElementsInRect:(CGRect)rect {
NSInteger minRow = (rect.origin.x > 0)? rect.origin.x/(kItemSize +20) : 0; // need to check because bounce gives negative values for x.
NSInteger maxRow = rect.size.width/(kItemSize +20) + minRow;
NSMutableArray* attributes = [NSMutableArray array];
for(NSInteger i=0 ; i < self.collectionView.numberOfSections; i++) {
for (NSInteger j=minRow ; j < maxRow; j++) {
NSIndexPath* indexPath = [NSIndexPath indexPathForItem:j inSection:i];
[attributes addObject:[self layoutAttributesForItemAtIndexPath:indexPath]];
}
}
return attributes;
}
До тех пор, пока Apple не добавит простой флаг для изменения ориентации макетов в макетах потоков, я заканчивал подклассами. Некоторые вещи специфичны для моей реализации, но могут помочь кому-то другому:
@interface UICollectionViewPagedFlowLayout : UICollectionViewFlowLayout
@property int width;
@property int height;
@end
@implementation UICollectionViewPagedFlowLayout
#warning MINOR BUG: sometimes items disappear
- (CGSize)collectionViewContentSize {
CGSize size = [super collectionViewContentSize];
size.width = self.collectionView.bounds.size.width * [self.collectionView numberOfSections];
return size;
}
- (NSArray*) layoutAttributesForElementsInRect:(CGRect)rect {
NSArray *array = [super layoutAttributesForElementsInRect:rect];
CGRect visibleRect;
visibleRect.origin = self.collectionView.contentOffset;
visibleRect.size = self.collectionView.bounds.size;
for (UICollectionViewLayoutAttributes* attributes in array) {
if (CGRectIntersectsRect(attributes.frame, rect)) {
// see which section this is in
CGRect configurableRect = UIEdgeInsetsInsetRect(visibleRect, self.sectionInset);
int horizontalIndex = attributes.indexPath.row % self.width;
int verticalIndex = attributes.indexPath.row / self.width;
double xspace = (configurableRect.size.width - self.width * self.itemSize.width) / self.width;
double yspace = (configurableRect.size.height - self.height * self.itemSize.height) / self.height;
attributes.center = CGPointMake(attributes.indexPath.section * visibleRect.size.width + self.sectionInset.left + (self.itemSize.width + xspace) * horizontalIndex + self.itemSize.width / 2, self.sectionInset.top + (self.itemSize.height + yspace) * verticalIndex + self.itemSize.height / 2);
}
}
return array;
}
@end