Objective c NSCollectionView是将NSCollectionViewItems绘制在彼此的上方

Objective c NSCollectionView是将NSCollectionViewItems绘制在彼此的上方,objective-c,macos,autolayout,nscollectionview,nscollectionviewitem,Objective C,Macos,Autolayout,Nscollectionview,Nscollectionviewitem,我的NSCollection视图正在将我的NSCollection项相互绘制。 更新:我添加了一个示例项目 更新:这有所改变 更新 我当前的示例有两个视图,它们当前位于自己的nib文件中,其中包含专用的NScollectionViewItem对象,它们当前用于测试的对象相同。我基本上有一个NSCollectionViewItem,它的子视图中有一个NSTextField。有了所有的限制 对于集合视图,它被设置为网格控制器,理想情况下,我希望有1列 为了加载数据,我将我的ViewControl

我的NSCollection视图正在将我的NSCollection项相互绘制。 更新:我添加了一个示例项目

更新:这有所改变

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

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

为了加载数据,我将我的ViewController设置为NSCollectionViewDataSource,并实现了
-(NSInteger)collectionView:(NSCollectionView*)collectionView numberOfItemsInSection:(NSInteger)section和
-(NSCollectionViewItem*)collectionView:(NSCollectionView*)collectionView
ItemForRepresentedObjectIndexPath:(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
中的View属性连接到
NSCollectionViewItem
。除默认约束外,当前没有任何约束

NSCollectionView
网格设置如下:

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

这是用于设置整个内容的代码,此时不将其绑定到数据源

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

我一直认为这是一个自动布局问题,因为最初有一些自动布局问题,但这些问题都已经解决了


任何帮助都将不胜感激。

数据数组应该保存数据,而不是
NSCollectionViewItem
s。在
collectionView:itemForRepresentedObjectAtIndexPath:
中调用
makeItemWithIdentifier:forIndexPath:
。调用
registerClass:forItemWithIdentifier:
Registernb:forItemWithIdentifier:
注册您的类或nib

更多信息,请参阅和的文档

编辑:

提供
NSCollectionViewItem
有两种方法

注册表类:forItemWithIdentifier:
。当集合视图需要一个新项时,它将恢复该类
NSCollectionViewItem
NSViewController
的子类,并且
NSViewController
查找与类同名的nib。
NSCollectionViewItem
是nib的所有者

注册表nb:forItemWithIdentifier:
。当集合视图需要新项时,它将加载此nib。
NSCollectionViewItem
是nib中的顶级对象

您将注册器类:forItemWithIdentifier:
与用于注册器的xib:forItemWithIdentifier:混合使用。使用注册表nb:forItemWithIdentifier:或修复xib。

我已经解决了它

并制作了一个github回购协议,该协议有一个工作版本

第一件事。由于Willeke对原始xib设置方式的理解,我能够使网格类型正常工作。但最终,如果你能让它做你想做的事情,成长视图是一种更好的视图类型,因为它支持截面、视图之间的距离等。因此,尽管我一开始想使用网格类型,但我将在我的应用程序中实现成长类型

因此,我使用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文件中定义,因此它们很容易修改


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

已经取得了一些进展!我从情节提要中删除了NSCollectionViewItems,并将它们与自定义类一起放在自己的NIB中。我注册了这些类,并将数组更改为包含标识符。这将在两个单独的列中加载两个视图,即使我将网格设置为一列。当我滚动视图时,两个NSCollectionViewItems又变成了一个。我尝试了你的代码,它工作了。当您从物品中删除所有违禁品时会发生什么?你是如何设置网格布局的?看来我可能一直在想这个都是错的。所以我在GitHub Repo中有一个工作版本,但它使用的是流而不是网格,从来没有按照我预期的方式使用网格。我可以通过使项目大小与视图大小一样大来创建单个列。所以这是一种工作。然而,我想看看我是否能有不同高度的观点谢谢Willeke的评论。我也有同样的想法。所以我对其进行了修改,使NSCollectionViewItems位于具有专用类的独立nib文件中。在视图控制器中,我注册了标识符,并将数组更改为标识符数组。在
itemForRepresentedObjectAtIndex
I
makeItemWi中