UICollectionView视图层优先级

时间:2013-08-16 21:13:39

标签: uicollectionview autolayout

我看到UICollectionViews的一个非常奇怪的行为。

以下是该方案。

我有一个UIViewController,已被推送到UINavigationController堆栈。

UIViewController视图在网格布局中有导航栏和UICollectionView。 3个细胞宽,无限高。

在屏幕范围之下,我还隐藏了一个UIToolbar。 UIToolbar位于层次结构中的UICollectionView之上。

然后我允许用户将视图放入“编辑模式”,我将UIToolbar设置为屏幕并覆盖UICollectionView的底部。如果用户离开“编辑模式”,我将UIToolbar移回屏幕。

在“编辑模式”下,我允许用户多选单元格,并显示复选框,uitoolbar有删除按钮。

删除执行以下操作:

- (void)deletePhotos:(id)sender {
if ([[self.selectedCells allKeys] count] > 0) {
    [[DataManager instance] deletePhotosAtIndexes:[self.selectedCells allKeys]];
    [self.selectedCells removeAllObjects];
    [self.collectionview reloadData];
    [self.collectionview performBatchUpdates:nil completion:nil];
}
}

// Data Manager method in singleton class:

- (void)deletePhotosAtIndexes:(NSArray *)indexes {
NSMutableIndexSet *indexesToDelete = [NSMutableIndexSet indexSet];
for (int i = 0; i < [indexes count]; i++) {
    [indexesToDelete addIndex:[[indexes objectAtIndex:i] integerValue]];
    NSString *filePath = [self.photosPath stringByAppendingPathComponent:[self.currentPhotos objectAtIndex:[[indexes objectAtIndex:i] integerValue]]];
    NSString *thumbnailPath = [self.thumbPath stringByAppendingPathComponent:[self.currentPhotos objectAtIndex:[[indexes objectAtIndex:i] integerValue]]];
    if ([[NSFileManager defaultManager] fileExistsAtPath: filePath]) {
        [[NSFileManager defaultManager] removeItemAtPath: filePath error:NULL];
        [[NSFileManager defaultManager] removeItemAtPath: thumbnailPath error:NULL];
    }
}
[self.currentPhotos removeObjectsAtIndexes:indexesToDelete];
}

数据管理器包含照片对象,用于创建单元格。

- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath{    
ImageCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:@"imageCell" forIndexPath:indexPath];

NSString  *pngfile = [[[DataManager instance] thumbPath] stringByAppendingPathComponent:[[[DataManager instance] currentPhotos] objectAtIndex:indexPath.row]];

if ([[NSFileManager defaultManager] fileExistsAtPath:pngfile]) {
    NSData *imageData = [NSData dataWithContentsOfFile:pngfile];
    UIImage *img = [UIImage imageWithData:imageData];
    [cell.imageView setImage:img];
}

if ([self.selectedCells objectForKey:[NSString stringWithFormat:@"%d", indexPath.row]] != nil) {
    cell.checkbox.hidden = NO;
} else {
    cell.checkbox.hidden = YES;
}

return cell;
}

所以这就是我发现问题的地方:

删除足够的单元格以使可见行数发生变化时,UIToolbar正在消失。如果是完整的3行,如果我只删除1或2个项目,则UIToolbar不会消失。我没有在删除方法中的UIToolbar上进行任何动画,只有在点击结束编辑模式的完成按钮时才会这样做。我已经确认没有调用此方法。

我也确认UIToolbar实际上并没有移动。如果我在UIToolbar正常消失的情况下在点击删除时添加“self.collectionview removeFromSuperView”,则UIToolbar正好在屏幕上预期的位置。这让我觉得UICollectionView在绘制父视图时会以某种方式改变层次结构。

我试图将Uuboolbar的SubviewToFront和sendSubviewToBack用于collectionview并且没有任何影响。

重新打开打开的工具栏会让uitoolbar重新生成动画。但奇怪的是,它似乎从屏幕下方动画了!这是没有意义的,除非UICollectionView以某种方式将UIToolbar推离屏幕,因为我将调用removeFromSuperview调用,因此我无法重新创建。

我的一个“解决方案”是强制UIToolbar返回到位,但在0.01秒延迟后没有动画

    [self performSelector:@selector(showToolbarNoAnimation) withObject:nil afterDelay:0.01];

这很有效。

以下是问题: 知道为什么UICollectionView导致此行为在删除完整行后将UIToolbar推送到屏幕外?黑客有效,但没有解释这个问题。

谢谢, 詹姆斯

1 个答案:

答案 0 :(得分:1)

使用自动布局时,您的视图是从故事板(或xib)加载的,您无法设置视图的框架。这样做似乎最初可行,但在某些时候,自动布局会根据约束重置视图的框架,你不会理解发生了什么,然后你会发一个问题到堆栈溢出。

如果需要更改视图的布局,则需要更新视图的约束。

有一个约束,指定工具栏底边与超视图底边之间的距离。大概距离是-44(其中44是工具栏的高度)。

您需要将该约束连接到视图控制器中的插座。插座的类型为NSLayoutConstraint *。称之为toolbarBottomEdgeConstraint

如果要将工具栏设置为屏幕动画,请将约束的constant设置为零并在动画块中调用layoutIfNeeded

- (void)showToolbarAnimated {
    [UIView animateWithDuration:0.25 animations:^{
        self.toolbarBottomEdgeConstraint.constant = 0;
        [self.toolbar layoutIfNeeded];
    }];
}

要隐藏工具栏,请将约束的constant恢复为原始值:

- (void)hideToolbarAnimated {
    [UIView animateWithDuration:0.25 animations:^{
        self.toolbarBottomEdgeConstraint.constant = -toolbar.bounds.size.height;
        [self.toolbar layoutIfNeeded];
    }];
}