NSCollectionView多选OSX Cocoa

时间:2016-02-11 15:10:42

标签: objective-c cocoa nscollectionview

我最近审核了一年前发布的我的一个应用程序。 而且我看到现在它里面的NSCollectionView已经失去了选择功能,例如SHIFT + Select现在它表现为CMD + Select而且我也无法用鼠标选择多个单元格(鼠标甚至没有绘制选择矩形)。

显然我想要这些功能。

我做了什么:

//NSCollectionView * _picturesGridView; //is my iVar

//In initialization I have set my _picturesGridView as follows
//Initializations etc are omitted -- (only the selection related code is here)
[_picturesGridView setSelectable:YES];
[_picturesGridView setAllowsMultipleSelection:YES];

问题:有没有简单的方法来取回此功能?我没有在文档中看到任何相关内容,我在互联网上找不到任何解决方案。

子问题:如果没有简单的方法可以实现这一点 - >我应该继续创建我自己的FancyPrefix##CollectionViewClass并按照我的意愿重新实现这个功能 - 或者更好地检查现有的NSCollectionView并强制它按照我的意愿行事?

子注意:好吧,如果我发现自己会重新实现它,它将是轻量级的,只会符合我自己的需要 - 我的意思是我不会模仿整个NSCollectionView类。

P.S。 我可以通过单击选择一个项目我只能通过CMD +单击或SHIFT +单击选择多个项目,但最后一个表现与CMD +单击我不想要的那样。

对于鼠标选择矩形 - 我没有覆盖任何鼠标事件。目前尚不清楚为什么我没有这个功能: - |

2 个答案:

答案 0 :(得分:0)

我从示例代码git@github.com:appcoda/PhotosApp.git开始,整理了一个示例,所有更改都在ViewController.swift中。

我通过添加来跟踪移位是向上还是向下

var shiftDown = false
override func flagsChanged(with event: NSEvent) {
    shiftDown = ((event.modifierFlags.rawValue >> 17) & 1) != 0
}

我添加了此实例变量以记住上一次选择

var lastIdx: IndexPath.Element?

然后,我在已经定义的collectionView(_:didSelectItemsAt)中添加

let thisIdx = indexPaths.first?[1]
if shiftDown, let thisIdx = thisIdx, let lastIdx = lastIdx {
    let minItem = min(thisIdx, lastIdx)
    let maxItem = max(thisIdx, lastIdx)
    var additionalPaths = Set<IndexPath>()
    for i in minItem...maxItem {
        additionalPaths.insert(IndexPath(item: i, section: 0))
    }
    collectionView.selectItems(at: additionalPaths, scrollPosition: [])
}
lastIdx = thisIdx

这只是一个开始。可能存在错误,尤其是在保存lastIdx周围。

答案 1 :(得分:0)

每Apple的文档,shouldSelectItemsAtIndexPaths:是事件仅被调用时与所述视图中的用户进行交互,而不是当所述选择是由自己的代码修改。因此,这种方法避免了使用didSelectItemsAt:时可能发生的副作用。

它的工作原理如下:

  1. 它需要记住先前单击的项目。此代码假定NSCollectionView实际上是一个名为CustomCollectionView的具有属性@property (strong) NSIndexPath * _Nullable lastClickedIndexPath;
  2. 的子类。
  3. 它仅记住上次单击的项目,它只是一次简单的选择单击,而不会记住(例如)具有多个选定项目的拖动选择。
  4. 如果按下Shift键检测到第二次单选单击,它将选择从最后一次单击到当前单击范围内的所有项目。
  5. 如果取消选择某个项目,我们将清除最后单击的项目,以便更好地模拟预期的行为。
- (NSSet<NSIndexPath *> *)collectionView:(CustomCollectionView *)collectionView shouldDeselectItemsAtIndexPaths:(NSSet<NSIndexPath*> *)indexPaths
{
    collectionView.lastClickedIndexPath = nil;
    return indexPaths;
}

- (NSSet<NSIndexPath *> *)collectionView:(CustomCollectionView *)collectionView shouldSelectItemsAtIndexPaths:(NSSet<NSIndexPath*> *)indexPaths
{
    if (indexPaths.count != 1) {
        // If it's not a single cell selection, then we also don't want to remember the last click position
        collectionView.lastClickedIndexPath = nil;
        return indexPaths;
    }
    NSIndexPath *clickedIndexPath = indexPaths.anyObject;   // now there is only one selected item
    NSIndexPath *prevIndexPath = collectionView.lastClickedIndexPath;
    collectionView.lastClickedIndexPath = clickedIndexPath; // remember last click
    BOOL shiftKeyDown = (NSEvent.modifierFlags & NSEventModifierFlagShift) != 0;
    if (NOT shiftKeyDown || prevIndexPath == nil) {
        // not an extension click
        return indexPaths;
    }
    NSMutableSet<NSIndexPath*> *newIndexPaths = [NSMutableSet set];
    NSInteger startIndex = [prevIndexPath indexAtPosition:1];
    NSInteger endIndex = [clickedIndexPath indexAtPosition:1];
    if (startIndex > endIndex) {
        // swap start and end position so that we can always count upwards
        NSInteger tmp = endIndex;
        endIndex = startIndex;
        startIndex = tmp;
    }
    for (NSInteger index = startIndex; index <= endIndex; ++index) {
        NSUInteger path[2] = {0, index};
        [newIndexPaths addObject:[NSIndexPath indexPathWithIndexes:path length:2]];
    }
    return newIndexPaths;
}

此答案已被称为“社区Wiki”,以便任何人都可以改进此代码。如果您发现错误或可以使其表现更好,请这样做。