【问题标题】:How to use NSCollectionViewItem without subclassing it?如何在不继承它的情况下使用 NSCollectionViewItem?
【发布时间】:2016-12-20 01:59:22
【问题描述】:

我正在编写一个非常简单的 macOS 应用程序,我想在集合视图中显示一些图像。对于它们的显示方式,我不需要任何特殊行为。 docs for NSCollectionViewItem 说:

该类的默认实现支持创建显示单个图像或字符串的简单项目。

这就是我想要的。但是,我找不到有关如何创建默认NSCollectionViewItem 的任何信息。

documentation for NSCollectionView 声明:

每个数据源对象都需要实现以下方法:

collectionView:numberOfItemsInSection:

collectionView:itemForRepresentedObjectAtIndexPath:

上面的第二种方法返回一个NSCollectionViewItem。通过阅读示例,我了解到在这种情况下创建 NSCollectionViewItem 的传统方法是调用:

NSCollectionViewItem*   newCollectionViewItem   = [imageCollectionView makeItemWithIdentifier:<some identifier>
                                                                                     forIndexPath:indexPath];

问题是我不明白&lt;some identifier&gt; 应该是什么。我没有包含NSCollectionViewItem 的笔尖,因为我没有对它进行子类化或以任何方式对其进行自定义。我尝试将以下内容添加到我的数据源中:

- (void)awakeFromNib
{
    [imageCollectionView registerClass:[NSCollectionViewItem class]
                 forItemWithIdentifier:@"Image"];
}

其中imageCollectionView 是有问题的NSCollectionView。然后在我的- (NSCollectionViewItem *)collectionView:itemForRepresentedObjectAtIndexPath: 方法中,我调用:

NSCollectionViewItem*   newCollectionViewItem   = [imageCollectionView makeItemWithIdentifier:@"Image"
                                                                                     forIndexPath:indexPath];

但这会引发异常并将其打印到控制台:

2016-12-19 17:51:27.463 MyApp[28177:3926764] -[NSNib _initWithNibNamed:bundle:options:] 无法加载 nibName: NSCollectionViewItem in bundle (null)。

随后是堆栈跟踪。

那么,我该如何创建和使用未以任何方式进行子类化或修改的NSCollectionViewItem

【问题讨论】:

  • 这是我的想法。第一,您应该说明您正在使用的 Xcode 版本。看来您使用的是 Xcode 7 或更低版本。自从引入 Xcode 8 以来,itemForRepresentedObjectAt 方法发生了变化。第 2 号,标识符是 NSCollectionViewItem xib 文件的名称。因此将“图像”设置为标识符没有意义。第 3 步,您应该只创建一个 collectionitem Xib 文件,除此之外。大约 3 到 4 周前我在 Swift 中做这件事时非常困难,因为 Swift 的信息有限。
  • 1.) 我在 macOS 10.11.6 上使用 Xcode 8.2。 2) 正如我所提到的,我没有 NSCollectionViewItem xib 文件,因此我无法为 .xib 文件提供标识符。此外,文档说您可以注册一个类而不是 .xib 文件,所以这可能是我想要做的(并尝试按照您在上面看到的那样做)。 3)这句话我看不懂,所以没有回应。
  • 哎呀......我本来打算写'除了它非常糟糕......' 据我所知,makeItemWithIdentifier 方法自 Xcode 8 以来已重命名为 makeItem。但如果你说你是使用 Xcode 8,我猜你正在使用 Xcode 8。好吧,祝你好运......
  • 我相信这是我几年前尝试做同样的事情(不使用 xib 文件作为收藏项)时用作参考的以下主题。 stackoverflow.com/questions/8660626/…看看有没有用。
  • 感谢您的链接。但是,在答案中,它们是我试图避免的 NSCollectionViewItem 的子类。文档说你不必继承它,我不想这样做。

标签: objective-c macos nscollectionview nscollectionviewitem


【解决方案1】:

这是一个非常简单的示例,它使用 Nib 作为项目的原型:

@interface ViewController()

@property (weak) IBOutlet NSCollectionView *collectionView;

@end

@implementation ViewController

- (void)viewDidLoad {
    [super viewDidLoad];
    NSNib *theNib = [[NSNib alloc] initWithNibNamed:@"Item" bundle:nil];

    [self.collectionView registerNib:theNib forItemWithIdentifier:@"item"];
}

#pragma mark NSCollectionViewDataSource

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

- (NSInteger)collectionView:(NSCollectionView *)inCollectionView numberOfItemsInSection:(NSInteger)inSection {
    return 10;
}

- (NSCollectionViewItem *)collectionView:(NSCollectionView *)inCollectionView itemForRepresentedObjectAtIndexPath:(NSIndexPath *)inIndexPath {
    NSCollectionViewItem *theItem = [inCollectionView makeItemWithIdentifier:@"item" forIndexPath:inIndexPath];
    NSTextField *theLabel = (NSTextField *)theItem.view;

    theLabel.stringValue = [NSString stringWithFormat:@"%d.%d", (int)inIndexPath.section, (int)inIndexPath.item];
    return theItem;
}

@end

NIB 仅包含一个 NSCollectionViewItem,并带有一个文本字段作为视图。

附录: 我认为您应该为 registerClass 变体创建一个NSCollectionViewItem.xib。如果您不在loadView 中手动创建视图,视图控制器将使用其类名搜索NIB。因此,您不能使用没有 NIB 的普通 NSCollectionViewItem 来注册类,因为 makeItemWithIdentifier:forIndexPath: 将访问项目的视图。

【讨论】:

  • 但是为什么需要NIB?为什么我们不能使用-registerClass: 而不是-registerNib:?为什么需要添加一个文本字段作为视图?文档说默认实现包括一个文本字段和一个图像视图。
  • 我添加了一个附录。
  • @user1118321 请检查以下链接,它将解决您对 -registerClass: 而不是 -registerNib:?: stackoverflow.com/questions/33396623/… 的困惑
  • 我不确定这应该告诉我什么。接受的答案是“所以你的收集单元格是用 nib 创建的,你应该在 nib 上注册。如果你的单元格完全用代码编写,你需要在 class 上注册。”就我而言,它完全在代码中 - 我使用默认的 NSCollectionViewItem,但注册该类不起作用。
  • 感谢您的回答。不幸的是它需要那么复杂。
【解决方案2】:

我找到了一种无需添加.xib 文件即可设置NSCollectionView 的方法。

诀窍是从NSCollectionViewItem 继承并将该子类用于-[NSCollectionView registerClass:forItemWithIdentifier:]

#import "ViewController.h"

@interface MyViewItem : NSCollectionViewItem
@end

@implementation MyViewItem {
}

- (instancetype)initWithNibName:(NSNibName)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil {
    self = [super initWithNibName:nil bundle:nil];
    
    NSButton *button = [[NSButton alloc] initWithFrame:NSZeroRect];
    [button setTitle:@"Button"];

    [self setView:button];
    
    return self;
}

@end

@implementation ViewController {
    IBOutlet NSCollectionView *_collectionView;
}

- (void)viewDidLoad {
    [super viewDidLoad];

    [_collectionView registerClass:[MyViewItem class]
             forItemWithIdentifier:@"item"];
    [_collectionView setDataSource:self];
}

- (NSInteger)collectionView:(NSCollectionView *)collectionView numberOfItemsInSection:(NSInteger)section {
    return 10;
}

- (NSCollectionViewItem *)collectionView:(NSCollectionView *)collectionView itemForRepresentedObjectAtIndexPath:(NSIndexPath *)indexPath {
    
    return [_collectionView makeItemWithIdentifier:@"item" forIndexPath:indexPath];
}

@end

【讨论】:

    猜你喜欢
    • 2012-05-13
    • 1970-01-01
    • 1970-01-01
    • 2018-09-13
    • 1970-01-01
    • 2015-11-25
    • 2020-09-26
    • 2013-01-21
    • 1970-01-01
    相关资源
    最近更新 更多