【问题标题】:NSCollectionView is drawing NSCollectionViewItems over each otherNSCollectionView 正在相互绘制 NSCollectionViewItems
【发布时间】:2017-11-19 22:07:53
【问题描述】:

我的 NSCollectionView 正在将我的 NSCollection 项目相互绘制。 更新:我添加了一个示例项目 GitHub Sample Project

更新:情况有所改变 When the app first launches it looks like this

更新 我当前的示例有两个视图,它们当前位于自己的 nib 文件中,具有专用的 NScollectionViewItem 对象,它们当前用于测试是相同的。我基本上有一个 NSCollectionViewItem 作为它的子视图,其中包含 NSTextField 。有所有的限制。

对于集合视图,它被设置为网格控制器,理想情况下,我希望有 1 列。

为了用数据加载它,我将 ViewController 设为 NSCollectionViewDataSource,并实现了 - (NSInteger)collectionView:(NSCollectionView *)collectionView numberOfItemsInSection:(NSInteger)section- (NSCollectionViewItem *)collectionView:(NSCollectionView *)collectionView itemForRepresentedObjectAtIndexPath:(NSIndexPath *)indexPath

更新代码 包含完整代码:

- (void)viewDidLoad {
    [super viewDidLoad];

    // Do any additional setup after loading the view.

    [collectionView registerClass:ItemOne.class forItemWithIdentifier:@"Item1"];
    [collectionView registerClass:ItemTwo.class forItemWithIdentifier:@"Item2"];

    cellArray = [@[@"Item1", @"Item2", @"Item1", @"Item2", @"Item1"] mutableCopy];
}


- (void)setRepresentedObject:(id)representedObject {
    [super setRepresentedObject:representedObject];

    // Update the view, if already loaded.
}

#pragma mark - NSCollectionViewDatasource -
- (NSInteger)collectionView:(NSCollectionView *)collectionView
 numberOfItemsInSection:(NSInteger)section {

    // We are going to fake it a little.  Since there is only one section
    NSLog(@"Section: %ld, count: %ld", (long)section, [cellArray count]);

    return [cellArray count];
}

- (NSCollectionViewItem *)collectionView:(NSCollectionView *)collectionView
 itemForRepresentedObjectAtIndexPath:(NSIndexPath *)indexPath {

    NSLog(@"IndexPath: %@, Requested one: %ld", indexPath, [indexPath item]);
    NSLog(@"Identifier: %@", [cellArray objectAtIndex:[indexPath item]]);

    NSCollectionViewItem *theItem = [collectionView makeItemWithIdentifier:[cellArray objectAtIndex:[indexPath item]] forIndexPath:indexPath];

    return theItem;
}

更新 ItemOne 和 ItemTwo 类都是空类,每个类的 nib 都有一个 NSCollectionViewItem,而后者又具有一个带有标签的视图。视图通过NSCollectionViewItem 中的视图属性连接到NSCollectionViewItem。目前除了默认的没有约束

NSCollectionView 网格设置如下:

布局:网格尺寸:最大行数:0 最大列数:1 最小项目大小: 宽度:250 高度:150 最大物品尺寸:宽度:250 高度:150

这是设置整个事物的代码,此时不将其绑定到数据源。

似乎无论我如何更改设置,甚至将 CollectionView 类型更改为 Flow 都不会改变任何内容,它看起来都一样。

我一直将此作为自动布局问题处理,因为最初存在一些自动布局问题,但这些问题都已解决。

任何帮助将不胜感激。

【问题讨论】:

  • 取得了一些进展!我从情节提要中删除了 NSCollectionViewItems 并将它们放在带有自定义类的自己的笔尖中。我注册了这些类,并更改了我的数组以包含标识符。即使我将网格设置为一列,它也会将两个视图加载到两个单独的列中。当我滚动视图时,两个 NSCollectionViewItems 再次合二为一。
  • 我试过你的代码,它可以工作。当您从项目中删除所有约束时会发生什么?您是如何设置网格布局的?
  • 看来我可能一直在想这一切都错了。所以我在 GitHub Repo 中有一个工作版本,但它适用于 Flow 而不是 Grid,从来没有让 Grid 以我期望的方式工作。并且能够通过使项目大小与视图大小一样大来创建单个列。所以这是一种工作。但是,我想看看我是否可以看到不同高度的视图

标签: objective-c macos autolayout nscollectionview nscollectionviewitem


【解决方案1】:

数据数组应该保存数据而不是NSCollectionViewItems。在collectionView:itemForRepresentedObjectAtIndexPath: 中,您调用makeItemWithIdentifier:forIndexPath:。致电registerClass:forItemWithIdentifier:registerNib:forItemWithIdentifier: 注册您的课程或笔尖。

NSCollectionViewcollectionView:itemForRepresentedObjectAtIndexPath:makeItemWithIdentifier:forIndexPath: 的文档中的更多信息。

编辑:

有两种方法可以提供NSCollectionViewItem

registerClass:forItemWithIdentifier:。当集合视图需要一个新项目时,它会实例化这个类。 NSCollectionViewItemNSViewController 的子类,NSViewController 查找与该类同名的 nib。 NSCollectionViewItem 是笔尖的所有者。

registerNib:forItemWithIdentifier:。当集合视图需要一个新项目时,它会加载这个 nib。 NSCollectionViewItem 是 nib 中的顶级对象。

您将registerClass:forItemWithIdentifier: 与用于registerNib:forItemWithIdentifier: 的xib 混合使用。使用registerNib:forItemWithIdentifier: 或修复xib。

【讨论】:

  • 感谢 cmets Willeke。我也有同样的想法。所以我对其进行了更改,以便 NSCollectionViewItems 位于具有专用类的单独 nib 文件中。在视图控制器中,我注册了标识符,并将数组更改为标识符数组。在itemForRepresentedObjectAtIndexmakeItemWithIdentifier 中,当应用程序首次加载时,所有项目都被分离出来,但一旦我执行滚动操作,它们就会相互结合。所以仍然不完全在那里,看起来滚动视图没有增长。
  • 好收获!即使我让它工作了,我已经修复了 Xib 不正确。现在我认为它可以以任何一种方式使用。由于流类型的附加功能,我仍然交换了网格类型
  • 我根据您的建议更新了 repo,并修复了 xib 文件,所以现在任何一个都可以工作。
【解决方案2】:

我想通了。

并制作了一个带有工作版本Working Version of Collection View Sample Application的github repo

第一件事。由于 Willeke 掌握了原始 xib 的设置方式,我能够让 Grid 类型正常工作。但最后,如果你可以让它做你想做的事情,Grow 视图是一种更好的视图类型,因为它支持部分,以及视图之间的距离等。所以即使我开始想要使用 Grid 类型,我将要实现我的应用中的 Grow 类型。

所以我使用 Grow 类型完成了单列视图。

我的成功标准是:

  • 它可以支持不统一的视图高度(每个自定义视图都可以有自己的高度)
  • 只有一列,如果视图大小扩大,每个自定义视图都会扩大。

进入源代码:

@interface ViewController ()
@property NSMutableArray *cellArray;
@property (weak) IBOutlet NSCollectionView *collectionView;

@end

@implementation ViewController

@synthesize cellArray;
@synthesize collectionView;

- (void)viewDidLoad {
    [super viewDidLoad];

    // Do any additional setup after loading the view.

    [collectionView registerClass:ItemOne.class forItemWithIdentifier:@"Item1"];
    [collectionView registerClass:ItemTwo.class forItemWithIdentifier:@"Item2"];

    cellArray = [@[@"Item1", @"Item2", @"Item1", @"Item2", @"Item1"] mutableCopy];
}


- (void)setRepresentedObject:(id)representedObject {
    [super setRepresentedObject:representedObject];

    // Update the view, if already loaded.
}

#pragma mark - NSCollectionViewDatasource -

- (NSInteger)numberOfSectionsInCollectionView:(NSCollectionView *)collectionView {
    return 1;
}

- (NSInteger)collectionView:(NSCollectionView *)collectionView
 numberOfItemsInSection:(NSInteger)section {

    // We are going to fake it a little.  Since there is only one section
    NSLog(@"Section: %ld, count: %ld", (long)section, [cellArray count]);

    return [cellArray count];
}

- (NSCollectionViewItem *)collectionView:(NSCollectionView *)collectionView
 itemForRepresentedObjectAtIndexPath:(NSIndexPath *)indexPath {

    NSLog(@"IndexPath: %@, Requested one: %ld", indexPath, [indexPath item]);
    NSLog(@"Identifier: %@", [cellArray objectAtIndex:[indexPath item]]);

    NSCollectionViewItem *theItem = [collectionView makeItemWithIdentifier:[cellArray objectAtIndex:[indexPath item]] forIndexPath:indexPath];

    theItem.representedObject = [cellArray objectAtIndex:[indexPath item]];

    return theItem;
}

#pragma mark - NSCollectionViewDelegate -
- (NSSize)collectionView:(NSCollectionView *)collectionView
              layout:(NSCollectionViewLayout *)collectionViewLayout sizeForItemAtIndexPath:(NSIndexPath *)indexPath {
    NSLog(@"%@", indexPath);

    NSSize size = NSMakeSize(438, 150);
    NSInteger width = 0;
    NSInteger height = 0;
    NSString *label = [cellArray objectAtIndex:[indexPath item]];

    NSRect collectionFrame = [collectionView frame];

    width = collectionFrame.size.width;

    // TODO: This needs to be based on the actual value of the view instead of hardcoding a number in.
    if ([label isEqualToString:@"Item1"]) {
        height = 114;
    } else if ([label isEqualToString:@"Item2"]) {
        height = 84;
    }

    size = NSMakeSize(width, height);

    return size;    
}

@end

你有它。实施还不错。 NSCollectionView 中显示的每个自定义视图都在其自己的 NSCollectionViewItem 和 .xib 文件中定义,因此它们很容易修改。

唯一脆弱的部分是我在计算每个视图的高度的地方,它之所以脆弱只是因为我在示例应用程序中的实现很懒惰。在实际实现中,我会从实际视图中动态抓取它们,这样它们就不会被绑定到一个静态数字。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-05-18
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多