iOS - 创建SpringBoard屏幕

时间:2014-05-28 14:34:26

标签: ios uiscrollview springboard

我正在尝试创建一个与iOS跳板屏幕相似的集合视图。 这意味着我希望拥有一个包含所有项目的集合视图,并在网格下面有一个页面控制器(就像跳板屏幕一样)。我还想实现相同的编辑模式,这意味着我的一个图标处于编辑模式,我可以将它们从一个页面拖到另一个页面,这样页面就不必满了。 我试图设置一个集合视图来水平滚动,但它没有按我的意愿行事。首先,图标在另一个下面添加,而在另一个旁边添加一个。其次,我没有这种方式的页面点,用户不能在不同的页面上放置图标 我还尝试设置页面控制器,并在每个页面中放入集合视图。在这种情况下,我在编辑模式下得到它,我不能进入屏幕之间。我想这是因为我有一个更多的集合视图,并且它们不会相互交互。 我用另一种方式,使用滚动视图,并尝试将集合视图放在该滚动视图中。但对我来说这听起来像是一个非常不优雅的解决方案。

有没有人知道如何创建这样的场景?

编辑: 我认为我的问题的答案隐藏在this question中。它描述了我想要的相同情况:一个集合视图,它是水平滚动的,带有分页,并且图标的顺序不是垂直流动,而是水平流动。那里有一个部分好的答案。我说它部分好,因为答案描述了UICollectionViewFlowLayout的子类,但是在上传的示例项目中,子类是UICollectionViewLayout,我认为重点是维护UICollectionViewFlowLayout具有的功能。 这个问题是在一年前提出来的,所以我相信某人有答案,或者至少我希望如此。

1 个答案:

答案 0 :(得分:3)

我对我的问题有部分解决方案。 我确实使用了linked question above的(波格丹)答案。这是代码:

layout.h:

#import <UIKit/UIKit.h>

@interface V9Layout : UICollectionViewLayout

@property (nonatomic, assign) NSInteger itemsInOneRow;
@property (nonatomic, assign) NSInteger itemsInOneCol;
@property (nonatomic, assign) CGSize itemSize;

@end

layout.m:

#import "V9Layout.h"

@interface V9Layout()

-(void)calculateLayoutProperties;
-(int)pagesInSection:(NSInteger)section;

@property (nonatomic, strong) NSMutableArray *frames;
@property (nonatomic, assign) CGFloat lineSpacing;
@property (nonatomic, assign) CGFloat interitemSpacing;
@property (nonatomic, assign) CGSize pageSize;    
@end

@implementation V9Layout

@synthesize itemsInOneRow = _itemsInOneRow, itemsInOneCol = _itemsInOneCol, itemSize = _itemSize;
@synthesize lineSpacing = _lineSpacing, interitemSpacing = _interitemSpacing;
@synthesize frames = _frames;

- (id)init
{
    self = [super init];
    if (self) {
        [self setup];
    }

    return self;
}

- (id)initWithCoder:(NSCoder *)aDecoder
{
    self = [super init];
    if (self) {
        [self setup];
    }

    return self;
}

- (void)setup
{
    self.itemsInOneRow = 3;
    self.itemsInOneCol = 4;
    self.frames = [NSMutableArray array];
}

-(void)calculateLayoutProperties {
    self.pageSize = self.collectionView.bounds.size;

    // The width of all line spacings is equal to width of ONE item. The same for interitem spacing

    CGFloat itemWidth = self.pageSize.width / (self.itemsInOneRow + 1); // +1 because we all spaces make width of one additional item
    CGFloat itemHeight = self.pageSize.height / (self.itemsInOneCol + 1); // the same
    NSLog(@"calculateLayoutProperties item width: %f, item height: %f", itemWidth, itemHeight);

    self.itemSize = CGSizeMake(itemWidth, itemHeight);
    // this part is only to make a global parameter, because I'm using this data to create the size of the UICollectionViewCell. I think I need to use a delegate method for the UICollectionViewCell to ask the UICollectionViewLayout for the calculated size of cell.
    NSUserDefaults *standardUserDefaults = [NSUserDefaults standardUserDefaults];

    if (standardUserDefaults) {
        [standardUserDefaults setObject:[NSNumber numberWithFloat:itemWidth] forKey:@"cellWidth"];
        [standardUserDefaults setObject:[NSNumber numberWithFloat:itemHeight] forKey:@"cellHeight"];
        [standardUserDefaults synchronize];
    }

    // spacing for x
    self.lineSpacing = (self.pageSize.width - (self.itemsInOneRow * self.itemSize.width)) / (self.itemsInOneRow + 1);
    // spacing for y
    self.interitemSpacing = (self.pageSize.height - (self.itemsInOneCol * self.itemSize.height)) / (self.itemsInOneCol + 1);
}

-(int)pagesInSection:(NSInteger)section {
    NSLog(@"v9layout: numberOfItemsInSection is %ld", (long)[self.collectionView numberOfItemsInSection:section]);
    return ([self.collectionView numberOfItemsInSection:section] - 1) / (self.itemsInOneRow * self.itemsInOneCol)  + 1;
}

-(CGSize)collectionViewContentSize {
    // contentSize.width is equal to pages * pageSize.width
    NSInteger sections = 1;
    if ([self.collectionView respondsToSelector:@selector(numberOfSections)]) {
        sections = [self.collectionView numberOfSections];
    }
    int pages = 0;
    for (int section = 0; section < sections; section++) {
        pages = pages + [self pagesInSection:section];
    }
    return CGSizeMake(pages * self.pageSize.width, self.pageSize.height);
}

-(void)prepareLayout {
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        [self calculateLayoutProperties];
    });

    [self.frames removeAllObjects];

    NSInteger sections = 1;
    if ([self.collectionView respondsToSelector:@selector(numberOfSections)]) {
        sections = [self.collectionView numberOfSections];
    }
    int pagesOffset = 0; // Pages that are used by prevoius sections
    int itemsInPage = self.itemsInOneRow * self.itemsInOneCol;
    for (int section = 0; section < sections; section++) {
        NSMutableArray *framesInSection = [NSMutableArray array];
        int pagesInSection = [self pagesInSection:section];
        int itemsInSection = [self.collectionView numberOfItemsInSection:section];
        for (int page = 0; page < pagesInSection; page++) {
            int itemsToAddToArray = itemsInSection - framesInSection.count;
            int itemsInCurrentPage = itemsInPage;
            if (itemsToAddToArray < itemsInPage) { // If there are less cells than expected (typically last page of section), we go only through existing cells.
                itemsInCurrentPage = itemsToAddToArray;
            }
            for (int itemInPage = 0; itemInPage < itemsInCurrentPage; itemInPage++) {
                CGFloat originX = (pagesOffset + page) * self.pageSize.width + self.lineSpacing + (itemInPage % self.itemsInOneRow) * (self.itemSize.width + self.lineSpacing);
                CGFloat originY = self.interitemSpacing + (itemInPage / self.itemsInOneRow) * (self.itemSize.height + self.interitemSpacing);
                CGRect itemFrame = CGRectMake(originX, originY, self.itemSize.width, self.itemSize.height);
                [framesInSection addObject:NSStringFromCGRect(itemFrame)];
            }
        }
        [self.frames addObject:framesInSection];

        pagesOffset += pagesInSection;
    }
}

-(NSArray *)layoutAttributesForElementsInRect:(CGRect)rect {
    NSMutableArray *attributes = [NSMutableArray array];

    NSInteger sections = 1;
    if ([self.collectionView respondsToSelector:@selector(numberOfSections)]) {
        sections = [self.collectionView numberOfSections];
    }

    int pagesOffset = 0;
    int itemsInPage = self.itemsInOneRow * self.itemsInOneCol;
    for (int section = 0; section < sections; section++) {
        int pagesInSection = [self pagesInSection:section];
        int itemsInSection = [self.collectionView numberOfItemsInSection:section];
        for (int page = 0; page < pagesInSection; page++) {
            CGRect pageFrame = CGRectMake((pagesOffset + page) * self.pageSize.width, 0, self.pageSize.width, self.pageSize.height);

            if (CGRectIntersectsRect(rect, pageFrame)) {
                int startItemIndex = page * itemsInPage;
                int itemsInCurrentPage = itemsInPage;
                if (itemsInSection - startItemIndex < itemsInPage) {
                    itemsInCurrentPage = itemsInSection - startItemIndex;
                }
                for (int itemInPage = 0; itemInPage < itemsInCurrentPage; itemInPage++) {
                    UICollectionViewLayoutAttributes *itemAttributes = [self layoutAttributesForItemAtIndexPath:[NSIndexPath indexPathForItem:startItemIndex + itemInPage inSection:section]];
                    if (CGRectIntersectsRect(itemAttributes.frame, rect)) {
                        [attributes addObject:itemAttributes];
                    }
                }
            }
        }

        pagesOffset += pagesInSection;
    }
    return attributes;
}

-(UICollectionViewLayoutAttributes *)layoutAttributesForItemAtIndexPath:(NSIndexPath *)indexPath {
    UICollectionViewLayoutAttributes *attributes = [UICollectionViewLayoutAttributes layoutAttributesForCellWithIndexPath:indexPath];
    attributes.frame = CGRectFromString(self.frames[indexPath.section][indexPath.item]);
    return attributes;
}

@end

这实现了水平分页,其中单元格的顺序彼此相邻而不是彼此之下。 我仍然想添加拖放功能,以便用户可以更改单元格的顺序。我对它提出了this question的意见。 希望我能找到答案并更新这个答案。