0

我看到 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 在绘制父视图时以某种方式改变了图层层次结构。

我试图尝试为 UIToolbar 带来SubviewToFront 和为 collectionview 带来 sendSubviewToBack 并且没有任何影响。

重新启动打开的工具栏会导致 uitoolbar 重新进入动画。然而,奇怪的是,它似乎是从屏幕下方开始动画的!这是没有意义的,除非 UICollectionView 在我将调用 removeFromSuperview 调用之后以某种方式将 UIToolbar 推离屏幕,因此我无法重新创建。

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

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

这行得通。

这是一个问题:知道为什么 UICollectionView 在删除整行后会导致此行为将 UIToolbar 推到屏幕外吗?hack有效,但没有解释问题。

谢谢,詹姆斯

4

1 回答 1

1

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

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

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

您需要将该约束连接到视图控制器中的插座。出口将有 type 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];
    }];
}
于 2013-08-19T16:32:32.173 回答