10.11 NSCollectionView-动态确定像元大小 [英] 10.11 NSCollectionView - determining cell size dynamically

查看:278
本文介绍了10.11 NSCollectionView-动态确定像元大小的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

OS X v10.11的AppKit发行说明建议可以根据每个项目调整集合视图项的大小:

AppKit Release Notes for OS X v10.11 suggests that collection view items can be resized on a per-item basis:

可以为CollectionView的所有项目全局确定项目大小(通过设置NSCollectionViewFlowLayout的"itemSize"属性),也可以在一个项目之间更改项目大小(通过在CollectionView的委托上实现-collectionView:layout:sizeForItemAtIndexPath:) ).

Item size can be determined globally for all of a CollectionView’s items (by setting an NSCollectionViewFlowLayout’s "itemSize" property), or can be varied from one item to the next (by implementing -collectionView:layout:sizeForItemAtIndexPath: on your CollectionView’s delegate).

在我的情况下,我的CollectionViewItem由单个标签组成,其中包含长度可变的字符串.我正在使用NSCollectionView来显示字符串数组,因为NSStackViews不支持数组绑定,也不会流到新行.字符串数组通过数组控制器绑定到NSCollectionView的内容.

In my case, my CollectionViewItem consists of a single label that contains a string of varying length. I'm using the NSCollectionView to display an array of strings, as NSStackViews don't support array bindings, and don't flow to new lines. The array of strings is bound to the NSCollectionView's content via an array controller.

我的物品的笔尖文件已正确设置,根视图和标签的 Content Hugging Content Compression Resistance 优先级均为1000,并且边缘通过自动版式.

My item's nib file is properly set up, the root view and the label both have Content Hugging and Content Compression Resistance Priorities of 1000, and the edges are aligned via AutoLayout.

现在,NSCollectionViewLayout的委托方法具有以下签名:

Now, the NSCollectionViewLayout's delegate method has this signature:

func collectionView(collectionView: NSCollectionView, 
                    layout collectionViewLayout: NSCollectionViewLayout, 
                    sizeForItemAtIndexPath indexPath: NSIndexPath) -> NSSize

我现在的想法是抓取物品本身,对其进行布局传递,然后返回新的物品尺寸.

My idea now is to grab the item itself, run a layout pass over it, and then returning the new item size.

let item = collectionView.itemAtIndexPath(indexPath)!
item.view.layout()
return item.view.bounds.size

此方法的问题是itemAtIndexPath返回nil.如果我在nil情况下返回默认大小,则该默认大小将用于所有单元格.

Problem with this approach is that itemAtIndexPath returns nil. If I return a default size in the nil case, that default size is used for all cells.

如何设置NSCollectionView来遵守我的商品的AutoLayout约束,并为每个单元动态地使用计算出的大小?

How can I set a NSCollectionView to respect my item's AutoLayout constraints and for each cell, use the computed size dynamically?

推荐答案

我回答了这个问题,但有一个重复,但这可能是因为它较老而应针对的问题.

There's a duplicate of this question that I answered but this is probably the one it should be directed to since it's older.

Juul的评论是正确的-该项目不存在.调用sizeForItemAt的是一个集合,该集合向委托人询问该数据条目的任何特定大小,它将用来帮助创建其最终的视图控制器NSCollectionViewItem.因此,当您要求集合使用它用来帮助获取项目的方法为您获取项目时,便会创建一个循环.

Juul's comment is correct- the items do not exist. sizeForItemAt being called is the collection asking the delegate for any specific sizing for that data entry with which it will use to help create its eventual view controller, NSCollectionViewItem. So you create a loop when you ask the collection to get you an item in the method that it uses to help get an item.

我们遇到的问题是,我们希望基于该数据的外观进行大小调整:具有正确格式的文本标签的长度,而不仅仅是字符串长度.因此,我们遇到了鸡蛋问题.

The problem we have is that we want sizing based on the appearance of that data: the length of a text label with proper formatting, not just, say, the string length. So we hit a chicken and egg problem.

我要提出的唯一解决方案可能是更漂亮的:

The only solution I've come to, which could be prettier, is the following:

  • 子类NSCollectionViewItem,并确保您的集合视图具有返回正确的子类项目的数据源.
  • 完全在XIB中使用约束.
  • 您的子类应该具有一个方法,该方法可以加载要表示的数据对象-为此,当然还有您的数据源协议方法.
  • 在第一次sizeForItemAt调用之前的某个时间点,或者,如果尚未到此,则在第一个调用的开始处手动创建NSCollectionViewItem子类的实例,并使用NSNib的instantiate(withOwner:topLevelObjects:)实例化您的子类作为所有者的XIB.将该引用存储为一种大小调整模板",因此您只需要执行一次即可.对我来说,委托是最容易的地方.
  • Subclass NSCollectionViewItem and ensure your collection view has a data source that returns the proper subclassed item.
  • Use constraints in your XIB, completely.
  • Your subclass should have a method that loads in the data object to be represented- both for this and of course your data source protocol methods.
  • At some point prior to the first sizeForItemAt call, or at the beginning of the first one if you hadn't by then, manually create an instance of your NSCollectionViewItem subclass, and use NSNib's instantiate(withOwner:topLevelObjects:) to instantiate its XIB with your subclass as an owner. Store that reference as a sort of "sizing template," so you only need to do it once. Delegate was easiest spot for me.

^ 注意:我的第一个方法是尝试通过集合的makeItemWithIdentifier进行此操作,但是它比较脆弱,因为它要求集合在创建大小调整模板时必须具有项目.在初始sizeForItemAt期间也无法完成此操作(在重新加载崩溃期间访问/制作项目).我担心,由于它是由集合制成的,因此可能会被重复使用,并且下面的方法不起作用或开始编辑可见项. YMMV.

^Note: my first route was to attempt this through the collection's makeItemWithIdentifier, but it was more brittle as it required the collection to have items at the time of creating the sizing template. It also could not be done during an initial sizeForItemAt (accessing/making items during a reload crashes). And I was worried that because it was made with the collection it may get reused down the line and the methods below don't work or start editing visible items. YMMV.

  • 直接从数据源获取要表示的数据对象.用我前面提到的方法让您的大小调整模板对象代表该数据对象.
  • 访问调整大小模板的View.FittingSize,可以为项目提供其限制/优先级的最小尺寸,然后返回.
  • Directly get the data object being represented from the datasource. Have your sizing template object represent that data object with the method I mentioned earlier.
  • Access the sizing template's View.FittingSize, the smallest size an item can be given its constraints/priorities, and return that.

Bam!尚未经过压力测试或其他任何测试,但是对我而言没有任何问题,并且它没有进行布局传递或其他任何操作,仅调用了FittingSize即可.我还没有在网上任何地方看到这一点,所以我想写出完整的解释.

Bam! Hasn't been stress tested or anything but no problems on my end, and its not doing a layout pass or anything, just calling FittingSize. I haven't seen this articulated anywhere online yet, so I wanted to write out the full explanation.

我是在Xamarin.Mac上执行此操作的,所以我的代码不会是1:1,并且我不想写乱码并弄乱任何东西.

I did this in Xamarin.Mac, so my code won't be 1:1 and I don't want to write garbled swift and mess anything up.

TLDR::手动实例化要存储的NSCollectionViewItem子类及其xib,该类不归集合所有.在sizeForItem期间,将您存储的项目用作尺寸参考,并返回集合项目视图的FittingSize.

TLDR: manually instantiate a NSCollectionViewItem subclass and its xib that you will store, unowned by the collection. During sizeForItem populate that item you store as a sizing reference, and return the FittingSize of the collection item's view.

这篇关于10.11 NSCollectionView-动态确定像元大小的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆