Yannis Calotychos
Yannis Calotychos

Reputation: 1

NSCollectionView, left align with Compositional Layout

I've been trying to implement a left aligned list of tokens, (NSTextField inside a box NSBox).

This is what I want to get:

enter image description here

I am using a NSCollectionView with Compositional Layout configured with :

The idea is that when the items get their actual field contents, autolayout constraints will automatically calculate the box width and place the items one after the other, wrapping to a new line for more items.

This never happens when the data snapshot is applied.

Instead what I get is this:

enter image description here

The interesting thing is that when I resize the enclosing window, the desired layout is achieved!!!

It looks like the first time the collection view is rendered using the estimated size.

Sample Code:

////

- (void)configureLayout
{
    float iWW = 80;
    float iHH = 16;
    
    ////////////////////
    // Item Definition
    
    NSCollectionLayoutSize *itemSize = [NSCollectionLayoutSize sizeWithWidthDimension:[NSCollectionLayoutDimension estimatedDimension:iWW]
                                                                      heightDimension:[NSCollectionLayoutDimension absoluteDimension:iHH]];
    NSCollectionLayoutItem *item = [NSCollectionLayoutItem itemWithLayoutSize:itemSize];

    
    ////////////////////
    // Group Definition
    
    NSCollectionLayoutSize *groupSize = [NSCollectionLayoutSize sizeWithWidthDimension:[NSCollectionLayoutDimension fractionalWidthDimension:1.0]
                                                                       heightDimension:[NSCollectionLayoutDimension estimatedDimension:iHH]];
    NSCollectionLayoutGroup *group = [NSCollectionLayoutGroup horizontalGroupWithLayoutSize:groupSize subitems:@[item]];

    group.interItemSpacing = [NSCollectionLayoutSpacing fixedSpacing:4.0];

    
    ////////////////////
    // Section Definition
    
    NSCollectionLayoutSection *section = [NSCollectionLayoutSection sectionWithGroup:group];
    NSCollectionLayoutSize *headerSize = [NSCollectionLayoutSize sizeWithWidthDimension:[NSCollectionLayoutDimension fractionalWidthDimension:1.0]
                                                                        heightDimension:[NSCollectionLayoutDimension absoluteDimension:22]];
    NSCollectionLayoutBoundarySupplementaryItem *sectionHeader = [NSCollectionLayoutBoundarySupplementaryItem
                                                                  boundarySupplementaryItemWithLayoutSize:headerSize
                                                                  elementKind:sectionHeaderElementKind
                                                                  alignment:NSRectAlignmentTop];
    section.boundarySupplementaryItems = @[sectionHeader];
    section.contentInsets = NSDirectionalEdgeInsetsMake(2, 0, 4, 10);
    section.interGroupSpacing = 4.0;


    ////////////////////
    // Prepare Layout
    
    collectionView.collectionViewLayout = [[NSCollectionViewCompositionalLayout alloc]initWithSection:section];
}

Upvotes: 0

Views: 644

Answers (1)

Jinwoo Kim
Jinwoo Kim

Reputation: 611

  1. Create NSCollectionViewDiffableDataSource+Private.h (.m file is not required)
#import <Cocoa/Cocoa.h>

NS_ASSUME_NONNULL_BEGIN

@interface NSCollectionViewDiffableDataSource (Private)
- (void)applySnapshot:(NSDiffableDataSourceSnapshot *)snapshot animatingDifferences:(BOOL)animatingDifferences completion:(void(^ _Nullable)(void))completion;
@end

NS_ASSUME_NONNULL_END
  1. on your applySnapshot:animatingDifferences: code, replace with:
#import "NSCollectionViewDiffableDataSource+Private.h"

[self.dataSource applySnapshot:snapshot animatingDifferences:NO completion:^{
    [self.collectionView.collectionViewLayout invalidateLayout];
}];

If you want to avoid using Private method, observe NSCollectionView's frame using NSViewFrameDidChangeNotification and call - [NSCollectionViewLayout invalidateLayout].

Upvotes: 0

Related Questions