NSCollectionView рисует NSCollectionViewItems друг над другом

Мой NSCollectionView рисует мои элементы NSCollection друг над другом. ОБНОВЛЕНИЕ: я добавил пример проекта Пример проекта GitHub

ОБНОВЛЕНИЕ: это несколько изменилось При первом запуске приложение выглядит так

ОБНОВЛЕНИЕ В моем текущем примере есть два представления, которые в настоящее время находятся в собственных файлах пера, с выделенными объектами 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 являются пустыми классами, кончик каждого из них имеет NSCollectionViewItem, который, в свою очередь, имеет представление с меткой. Представление связано с NSCollectionViewItem свойством представления в NSCollectionViewItem. В настоящее время нет ограничений, кроме ограничений по умолчанию.

Сетка NSCollectionView настроена следующим образом:

Макет: Размер сетки: Максимальное количество строк: 0 Максимальное количество столбцов: 1 Минимальный размер элемента: Ширина: 250 Высота: 150 Максимальный размер элемента: Ширина: 250 Высота: 150

Это код для настройки всего этого, на данный момент не привязывая его к источнику данных.

Кажется, что какие бы я ни меняла настройки или даже меняла тип CollectionView на Flow, ничего не меняется, он выглядит одинаково.

Я подходил к этому как к проблеме AutoLayout, потому что изначально были некоторые проблемы с автоматическим макетом, но все они были решены.

Любая помощь будет принята с благодарностью.


person Tempus    schedule 17.06.2017    source источник
comment
Достигли некоторого прогресса! Я удалил NSCollectionViewItems из раскадровки и поместил их в собственные перья с пользовательскими классами. Я зарегистрировал классы и изменил свой массив, включив в него идентификатор. Который загружает оба представления в два отдельных столбца, хотя у меня есть сетка, установленная в один столбец. Как только я прокручиваю представление, два элемента NSCollectionViewItem снова становятся одним целым.   -  person Tempus    schedule 17.06.2017
comment
Я попробовал ваш код, и он работает. Что происходит, когда вы удаляете все ограничения из элементов? Как вы настроили сетку?   -  person Willeke    schedule 18.06.2017
comment
Кажется, я мог думать обо всем этом неправильно. Итак, у меня есть рабочая версия в репозитории GitHub, но она работает с Flow, а не с Grid, никогда Grid не работал так, как я ожидал. И я могу создать один столбец, сделав размер элемента таким же большим, как размер представления. Так вроде работает. Тем не менее, я хочу посмотреть, могу ли я иметь виды с разной высотой   -  person Tempus    schedule 21.06.2017


Ответы (2)


Массив данных должен содержать данные вместо NSCollectionViewItems. В collectionView:itemForRepresentedObjectAtIndexPath: вы звоните makeItemWithIdentifier:forIndexPath:. Позвоните registerClass:forItemWithIdentifier: или registerNib:forItemWithIdentifier:, чтобы зарегистрировать свой класс или nib.

Дополнительные сведения см. в документации по NSCollectionView, collectionView:itemForRepresentedObjectAtIndexPath: и makeItemWithIdentifier:forIndexPath:.

РЕДАКТИРОВАТЬ:

Есть два способа предоставить файл NSCollectionViewItem.

registerClass:forItemWithIdentifier:. Когда представлению коллекции требуется новый элемент, оно создает этот класс. NSCollectionViewItem является подклассом NSViewController, а NSViewController ищет перо с тем же именем, что и класс. NSCollectionViewItem является владельцем пера.

registerNib:forItemWithIdentifier:. Когда представлению коллекции требуется новый элемент, оно загружает этот наконечник. NSCollectionViewItem — это объект верхнего уровня пера.

Вы смешали registerClass:forItemWithIdentifier: с xib для использования с registerNib:forItemWithIdentifier:. Используйте registerNib:forItemWithIdentifier: или исправьте xib.

person Willeke    schedule 17.06.2017
comment
Спасибо за комментарии Виллеке. У меня была такая же мысль. Поэтому я изменил его, чтобы NSCollectionViewItems находились в отдельных файлах пера с выделенными классами. В контроллере представления я регистрирую идентификаторы и изменяю массив на массив идентификаторов. В itemForRepresentedObjectAtIndex I makeItemWithIdentifier и при первой загрузке приложения все элементы разделены, но как только я выполняю действие прокрутки, они объединяются друг с другом. Так что все еще не совсем там, кажется, что прокрутка не растет. - person Tempus; 18.06.2017
comment
Хороший улов! Несмотря на то, что я заработал, Xib был неправильным, что я исправил. И теперь я думаю, что его можно использовать в любом случае. Я все еще заменил тип сетки из-за добавленной функциональности типа потока. - person Tempus; 22.06.2017
comment
Я обновил репозиторий с вашими предложениями и исправил xib-файлы, так что теперь любой из них должен работать. - person Tempus; 22.06.2017

Я разобрался.

И сделал репозиторий github с рабочей версией Рабочая версия приложения Collection View Sample Application

Первым делом. Благодаря уловке Виллеке того, как был настроен оригинальный 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, поэтому их легко модифицировать.

Единственная хрупкая часть — это то, где я вычисляю высоту каждого представления, и она хрупкая только потому, что я ленив в своей реализации в примере приложения. В фактической реализации я буду динамически извлекать их из реальных представлений, чтобы они не были привязаны к статическому числу.

person Tempus    schedule 22.06.2017