0

我有一个NSCollectionView正在显示一些图像。我已经实现了一个NSCollectionViewDelegate告诉它应该选择和/或突出显示哪些项目。我正在使用股票NSCollectionViewItem来绘制图像及其名称。当用户选择一个项目时,我的代表会收到有关突出显示状态更改的消息:

- (void)collectionView:(NSCollectionView *)collectionView
didChangeItemsAtIndexPaths:(NSSet<NSIndexPath *> *)indexPaths
      toHighlightState:(NSCollectionViewItemHighlightState)highlightState
{
    [collectionView reloadItemsAtIndexPaths:indexPaths];
}

我为didSelect/做了类似的事情didDeselect

- (void)collectionView:(NSCollectionView *)collectionView
didSelectItemsAtIndexPaths:(nonnull NSSet<NSIndexPath *> *)indexPaths
{
    [collectionView reloadItemsAtIndexPaths:indexPaths];
}

NSCollectionViewItemsview中,我执行以下操作:

- (void)drawRect:(NSRect)dirtyRect {
    [super drawRect:dirtyRect];

    NSColor*    bgColor         = [[self window] backgroundColor];
    NSColor*    highlightColor  = [NSColor selectedControlColor];

    NSRect  frame  = [self bounds];
    NSCollectionViewItemHighlightState  hlState     = [collectionViewItem highlightState];
    BOOL                                selected    = [collectionViewItem isSelected];
    if ((hlState == NSCollectionViewItemHighlightForSelection) || (selected))
    {
        [highlightColor setFill];
    }
    else
    {
        [bgColor setFill];
    }
    [NSBezierPath fillRect:frame];
}

我看到的问题是绘制突出显示或选择似乎是随机的。当它绘制选择时,它几乎总是在用户实际选择的项目上(尽管由于某种原因它经常忽略最后一个项目)。有时,它会选择用户没有点击或拖过的不同项目。但是,通常它只是不绘制。

我添加了打印以验证它是否正在调用-didChangeItemsAtIndexPaths:toHighlightState:-didSelectItemsAtIndexPaths:. 我在这里做错了什么吗?

我在视图的-drawRect:方法中添加了一些日志记录,即使我-reloadItemsAtIndexPaths:-didChange*方法中调用,它似乎也没有在所有转换中被调用。为什么不?

我还注意到,委托-should/didDeselectItemsAtIndexPaths:似乎从未被调用过,即使-should/didSelectItemsAtIndexPaths:确实被调用过。这是为什么?

4

1 回答 1

4

问题原来是调用[collectionView reloadItemsAtIndexPaths:]。当您这样做时,它会删除现有的NSCollectionViewItem并创建一个新的(通过调用您的数据源的collectionView:itemForRepresentedObjectAt:)。这会立即将新的集合视图项设置为未选中(或者更确切地说,它没有将其设置为选中)。发生这种情况时,它不会调用您的should/didDeselect方法,因为现有项目不再存在,并且未选择新项目。

真正的解决方案是子类化NSCollectionViewItem并覆盖-setSelected:以执行以下操作:

- (void)setSelected:(BOOL)selected
{
    [super setSelected:selected];
    [self.view setNeedsDisplay:YES];
}

当视图的-drawRect:方法被调用时,它会询问项目是否被选中并适当地绘制。

should/did/select/Deselect因此,我可以毫无问题地完全删除委托中的所有方法,并且一切正常!

于 2017-01-25T02:32:05.487 回答