如何在 NSCollectionView 中正确显示当前选择?
How to properly show the current selection in an NSCollectionView?
我有一个 NSCollectionView
正在显示一些图像。我已经实现了一个 NSCollectionViewDelegate
来告诉它应该 selected and/or 突出显示哪些项目。我正在使用股票 NSCollectionViewItem
来绘制图像及其名称。当用户 select 一个项目时,我的代表会收到关于突出显示状态更改的消息:
- (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];
}
在 NSCollectionViewItem
s view
中,我执行以下操作:
- (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];
}
我看到的问题是绘制高光或 selection 似乎是随机的。当它确实绘制 selection 时,它几乎总是在用户实际 selected 的项目上(尽管由于某种原因它通常会遗漏最后一个项目)。有时,它会 select 用户没有点击或拖过的不同项目。但是,通常它只是不绘制。
我添加了打印以验证它正在调用 -didChangeItemsAtIndexPaths:toHighlightState:
和 -didSelectItemsAtIndexPaths:
。我在这里做错了什么吗?
我已经在视图的 -drawRect:
方法中添加了一些日志记录,它似乎并没有在所有转换中被调用,即使我在 -didChange*
方法。为什么不?
我还注意到代表的 -should/didDeselectItemsAtIndexPaths:
似乎从未被调用过,尽管 -should/didSelectItemsAtIndexPaths:
确实被调用过。这是为什么?
原来是调用[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
方法,并且一切正常!
我有一个 NSCollectionView
正在显示一些图像。我已经实现了一个 NSCollectionViewDelegate
来告诉它应该 selected and/or 突出显示哪些项目。我正在使用股票 NSCollectionViewItem
来绘制图像及其名称。当用户 select 一个项目时,我的代表会收到关于突出显示状态更改的消息:
- (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];
}
在 NSCollectionViewItem
s view
中,我执行以下操作:
- (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];
}
我看到的问题是绘制高光或 selection 似乎是随机的。当它确实绘制 selection 时,它几乎总是在用户实际 selected 的项目上(尽管由于某种原因它通常会遗漏最后一个项目)。有时,它会 select 用户没有点击或拖过的不同项目。但是,通常它只是不绘制。
我添加了打印以验证它正在调用 -didChangeItemsAtIndexPaths:toHighlightState:
和 -didSelectItemsAtIndexPaths:
。我在这里做错了什么吗?
我已经在视图的 -drawRect:
方法中添加了一些日志记录,它似乎并没有在所有转换中被调用,即使我在 -didChange*
方法。为什么不?
我还注意到代表的 -should/didDeselectItemsAtIndexPaths:
似乎从未被调用过,尽管 -should/didSelectItemsAtIndexPaths:
确实被调用过。这是为什么?
原来是调用[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
方法,并且一切正常!