Подтвердить что ты не робот

Вызов setCollectionViewLayout: анимированный не перезагружает UICollectionView

Я использую UICollectionView с двумя настраиваемыми макетами, которые подклассы из UICollectionViewFlowLayout

Когда мой просмотр сначала загружается, я задал его по умолчанию, используя:

[self.collectionView setCollectionViewLayout:self.tableViewLayout];

Это вызывает: cellForItemAtIndexPath - поэтому проблем нет. Это находится в методе viewWillAppear.

Затем я использую UIButton для изменения макета из текущего вида на следующий макет, например:

-(void)changeViewLayoutButtonPressed
{
    self.changeLayout = !self.changeLayout;


    if (self.changeLayout){

        [self.tradeFeedCollectionView setCollectionViewLayout:self.grideLayout animated:YES];

    }

    else {


        [self.tradeFeedCollectionView setCollectionViewLayout:self.tableViewLayout animated:YES];

    }
}

После вызова этого вызова - numberOfItemsInSection. Я проверил в отладчике, что возвращаемая учетная запись не равна нулю.

После этого вызова ничего не вызывается, и мой UICollectionView меняет макет, но поскольку cellForItemAtIndexPath не вызывается - ячейки не настроены правильно.

если я помещаю [self.collectionView roloadData] внутри numberOfItemsInSection - тогда вызывается cellForItemAtIndexPath и устанавливаются ячейки.

Мне не нужно выполнять ручной вызов для перезагрузки данных в numberOfItemsInSection. Может кто-нибудь сказать мне, что происходит?

Edit

Я забыл упомянуть, что я использую два разных UINib для двух разных ячеек, поскольку им нужны несколько разные макеты, применяемые к ним. Будет ли это проблемой? Спасибо!

Изменить 2

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

Пользовательские макеты

Они подклассифицированы из UICollectionViewFlowLayout. Причина, по которой я подклассифицирован, просто из-за лица, которому мой UICollectionView должен выглядеть и вести себя очень близко к готовому макету Apple. Однако разные размеры ячеек.

TableViewLayout - Нет кода в файле заголовка.   - BBTradeFeedTableViewLayout.m

@implementation BBTradeFeedTableViewLayout

-(id)init
{
    self = [super init];

    if (self){

        self.itemSize = CGSizeMake(320, 80);
        self.minimumLineSpacing = 0.1f;
    }

    return self;
}
@end

Макет Gride - Нет кода в файле заголовка.   - BBTradeFeedGridViewLayout.m

   @implementation BBTradeFeedGridViewLayout

-(id)init
{
    self = [super init];

    if (self){

        self.itemSize = CGSizeMake(159, 200);
        self.minimumInteritemSpacing = 0.1f;
        self.minimumLineSpacing = 0.1f;
    }
    return self; 
}
@end

Затем в ViewController, у которого есть мой UICollectionView - я объявляю два пользовательских макета, например:

@property (strong, nonatomic) BBTradeFeedTableViewLayout *tableViewLayout;
@property (strong, nonatomic) BBTradeFeedGridViewLayout *grideLayout;

Затем я регистрирую два .xib файла для коллекции:

  [self.tradeFeedCollectionView registerNib:[UINib nibWithNibName:@"BBItemTableViewCell" bundle:nil] forCellWithReuseIdentifier:@"TableItemCell"];
        [self.tradeFeedCollectionView registerNib:[UINib nibWithNibName:@"BBItemGridViewCell" bundle:nil] forCellWithReuseIdentifier:@"GridItemCell"];

Затем у меня есть UIButton, который меняет макет:

    -(void)changeViewLayoutButtonPressed
{

    if (!self.gridLayoutActive){

        self.gridLayoutActive = YES;
        [self.tradeFeedCollectionView setCollectionViewLayout:self.grideLayout animated:YES];
        self.lastLayoutUsed = @"GridLayout";

    }

    else {

        self.gridLayoutActive = NO;

        [self.tradeFeedCollectionView setCollectionViewLayout:self.tableViewLayout animated:YES];
        self.lastLayoutUsed = @"TableLayOut";
    }
    [self.tradeFeedCollectionView reloadItemsAtIndexPaths:[self.tradeFeedCollectionView indexPathsForVisibleItems]];

}

Наконец - когда вызов веб-службы завершен - он вызывает [self.tradeFeedCollectionView reloadData];

Итак, мой UICollectionView получает перезагрузку и последний метод:

 -(UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath

{   static NSString *tableCellIdentifier = @"TableItemCell";
    static NSString *gridCellIdentifier = @"GridItemCell";

    if (indexPath.item < [self.tradeSearchArray count]){

    if (self.gridLayoutActive == NO){

        BBItemTableViewCell *tableItemCell = [collectionView dequeueReusableCellWithReuseIdentifier:tableCellIdentifier forIndexPath:indexPath];

    if ([self.tradeSearchArray count] > 0){

        self.toolBarButtomItem.title = [NSString stringWithFormat:@"%d Results", self.searchResult.searchResults];

        tableItemCell.gridView = NO;
        tableItemCell.backgroundColor = [UIColor whiteColor];
        tableItemCell.item = self.tradeSearchArray[indexPath.row];

    }
        return tableItemCell;
}else

    {

        BBItemTableViewCell *gridItemCell= [collectionView dequeueReusableCellWithReuseIdentifier:gridCellIdentifier forIndexPath:indexPath];

    if ([self.tradeSearchArray count] > 0){

        self.toolBarButtomItem.title = [NSString stringWithFormat:@"%d Results", self.searchResult.searchResults];


        gridItemCell.gridView = YES;
        gridItemCell.backgroundColor = [UIColor whiteColor];
        gridItemCell.item = self.tradeSearchArray[indexPath.row];

    }

    return gridItemCell;
    }

Проблема с приведенным выше кодом

Вышеприведенный код действительно работает. Тем не менее, клетки не ожидают красиво, и это выглядит странно, почти как если бы произошло обновление. Который вызван:

[self.tradeFeedCollectionView reloadItemsAtIndexPaths:[self.tradeFeedCollectionView indexPathsForVisibleItems]];

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

4b9b3361

Ответ 1

-setCollectionViewLayout: или -setCollectionViewLayout:animated: не приведет к перезагрузке UICollectionView.

  • Если вы хотите изменить стиль ячейки или обновить данные, вызовите методы протокола [self.collectionView reload] и UICollectionViewDataSource.
  • Если вы хотите изменить макет UICollectionView на другой, вызовите -setCollectionViewLayout:. Или, если вы хотите обновить макет UICollectionView, просто позвоните [self.collectionView.collectionViewLayout invalidateLayout].

Раскладка и данные ячеек - это две разные вещи в UICollectionView.

Обновление
вы должны отбросить все устаревшие данные, возможно, на -reloadData. И вычислить новые кадры для каждой ячейки в подклассах UICollectionViewLayout. Переопределить - (UICollectionViewLayoutAttributes *)layoutAttributesForItemAtIndexPath:(NSIndexPath *)indexPath и - (NSArray *)layoutAttributesForElementsInRect:(CGRect)rect.
Вы выбираете новый contentOffset. Например, вы можете сохранить indexPath некоторой видимой ячейки и решить прокрутить до indexPath или setContentOffset: к frame.origin новой ячейки в том же indexPath после изменения макета.

Ответ 2

Просто позвоните reloadData перед, вы переключите свой макет (вызов performBatchUpdates не является обязательным):

[self.collectionView reloadData];
[self.collectionView.collectionViewLayout invalidateLayout];
[self.collectionView setCollectionViewLayout:yourLayout animated:YES];

В Swift:

self.collectionView?.reloadData()
self.collectionView?.collectionViewLayout.invalidateLayout()
self.collectionView?.setCollectionViewLayout(yourLayout, animated: true)

Ответ 3

Вы должны называть [self.tradeFeedCollectionView invalidateLayout]; до

if (self.changeLayout){
    [self.tradeFeedCollectionView setCollectionViewLayout:self.grideLayout animated:YES];
}
else {
    [self.tradeFeedCollectionView setCollectionViewLayout:self.tableViewLayout animated:YES];
}

Ответ 4

Вам нужно только вызвать этот метод:

[self.collectionView setCollectionViewLayout:layout animated:YES];

У меня была подобная ошибка, но оказалось, что мои подзаголовки ячеек не были настроены с помощью Auto Layout. Ячейка правильно изменяла размер, но мои подзаголовки не были, поэтому он выглядел так, как размер ячейки никогда не менялся. Проверьте это в своем коде быстро, установив clipToBounds = YES на свой cell.contentView.

Ответ 5

Вот простой трюк, если вы хотите обновлять макеты. Используйте его везде, где вы обновляете collectionView:

[self.collectionView removeFromSuperview]; //First remove the Collection View

//Relocate the view with layouts
UICollectionViewFlowLayout *layout=[[UICollectionViewFlowLayout alloc] init];
layout.scrollDirection = UICollectionViewScrollDirectionHorizontal;
layout.minimumInteritemSpacing = 10;
layout.minimumLineSpacing = 10;

 self.collectionView = [[UICollectionView alloc] initWithFrame:CGRectMake(0, 0, self.view.frame.width,100) collectionViewLayout:layout];
[self.collectionView setDataSource:self];
[self.collectionView setDelegate:self];
[self.collectionView registerClass:[UICollectionViewCell class] forCellWithReuseIdentifier:@"cellIdentifier"];
[self.collectionView reloadData];

[self.view addSubview:self.collectionView];

Ответ 6

(Отправлено решение от имени автора вопроса).

Наконец-то я нашел хорошее и простое решение.

Отмеченный ответ был правильным, что мне нужно было вызвать -reloadData на моем UICollectionView. Однако это уничтожило анимацию при переключении между двумя ячейками.

После принятия предложений от отмеченного ответа - я только переработал свой метод "UIButton", который меняет ячейки

Я обнаружил, что если я позвоню:

[self.collectionview performBatchUpdates:^{  } completion:^(BOOL finished) {

}];

В соответствии с видео WDDC - это оживляет изменения с помощью метода -reloadData:

Пример:

[self.collectionView reloadData]; 
    [self.collectionView performBatchUpdates:^{
        [self.collectionView.collectionViewLayout invalidateLayout];
        [self.collectionView setCollectionViewLayout:self.grideLayout animated:YES];
    } completion:^(BOOL finished) {

    }];
}