UICollectionView: изменение размера ячейки для анимации при выборе

Что я хочу сделать, это изменить размер UICollectionViewCell и анимировать это изменение, когда ячейка выбрана. Я уже успел сделать это без изменений, отметив ячейку, выбранную в collectionView: didSelectItemAtIndexPath:, а затем вызвав reloadData в моем UICollectionView, отобразив выделенную ячейку с другим размером.

Тем не менее, это происходит сразу, и я не знаю, как получить это изменение в анимированном размере. Любые идеи?

Я уже нашел Анимировать ячейки uicollectionview при выборе, но ответ был неспецифичным для меня, и я еще не понял, может ли он помочь мне в моем случай.

Ответ 1

[UIView transitionWithView:collectionView 
                  duration:.5 
                   options:UIViewAnimationOptionTransitionCurlUp 
                animations:^{

    //any animatable attribute here.
    cell.frame = CGRectMake(3, 14, 100, 100);

} completion:^(BOOL finished) {

    //whatever you want to do upon completion

}];

Поиграйте с чем-то в этих строках внутри вашего метода didselectItemAtIndexPath.

Ответ 2

С помощью Chase Roberts я нашел решение своей проблемы. Мой код в основном выглядит следующим образом:

// Prepare for animation

[self.collectionView.collectionViewLayout invalidateLayout];
UICollectionViewCell *__weak cell = [self.collectionView cellForItemAtIndexPath:indexPath]; // Avoid retain cycles
void (^animateChangeWidth)() = ^()
{
    CGRect frame = cell.frame;
    frame.size = cell.intrinsicContentSize;
    cell.frame = frame;
};

// Animate

[UIView transitionWithView:cellToChangeSize duration:0.1f options: UIViewAnimationOptionCurveLinear animations:animateChangeWidth completion:nil];

Для дальнейшего объяснения:

  • Одним из наиболее важных шагов является вызов invalidateLayout на UICollectionView.collectionViewLayout, который вы используете. Если вы забудете это, вероятно, произойдет, что клетки будут расти над границами вашей коллекции - это то, что вы, скорее всего, не захотите. Также подумайте, что ваш код должен в какой-то момент представить новый размер вашей ячейки для вашего макета. В моем случае (я использую UICollectionViewFlowLayout), я скорректировал метод collectionView:layout:sizeForItemAtIndexPath, чтобы отразить новый размер измененной ячейки. Забыв эту часть, ничего не произойдет с вашими размерами ячеек, если вы сначала вызовете invalidateLayout, а затем попытайтесь оживить изменение размера.

  • Самое странное (по крайней мере для меня), но важно то, что вы вызываете invalidateLayout не внутри блока анимации. Если вы это сделаете, анимация не будет отображаться гладко, но глючит и мерцает.

  • Вы должны вызвать метод UIView transitionWithView:duration:options:animations:completion: с ячейкой в ​​качестве аргумента для transitionWithView, а не весь вид коллекции, потому что это ячейка, которую вы хотите оживить, а не всю коллекцию.

  • Я использовал метод intrinsicContentSize моей ячейки, чтобы вернуть размер, который я хочу, - в моем случае я выращиваю и сокращаю ширину ячейки, чтобы либо отображать кнопку, либо скрывать ее, в зависимости от состояния выбора ячейки.

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

Ответ 3

Анимация размера ячейки работает так же, как и для представлений коллекции, как и для табличных представлений. Если вы хотите оживить размер ячейки, у вас есть модель данных, которая отражает состояние ячейки (в моем случае я просто использую флаг (CollectionViewCellExpanded, CollectionViewCellCollapsed) и соответственно возвращаю CGSize.

Когда вы вызываете и пустите вызов executeBathUpdates, вид автоматически анимируется.

- (void)collectionView:(UICollectionView *)collectionView didSelectItemAtIndexPath:(NSIndexPath *)indexPath
{
    [collectionView performBatchUpdates:^{
        // append your data model to return a larger size for
        // cell at this index path
    } completion:^(BOOL finished) {

    }];
}

Ответ 4

У меня была успешная анимация изменений с помощью -setCollectionViewLayout:animated:, чтобы создать новый экземпляр того же макета представления коллекций.

Например, если вы используете UICollectionViewFlowLayout, то:

// Make sure that your datasource/delegate are up-to-date first

// Then animate the layout changes
[collectionView setCollectionViewLayout:[[UICollectionViewFlowLayout alloc] init] animated:YES];

Ответ 5

Это самое простое решение, которое я нашел - работает как шарм. Плавная анимация и не испортит макет.

Свифта

    collectionView.performBatchUpdates({}){}

Obj-C

    [collectionView performBatchUpdates:^{ } completion:^(BOOL finished) { }];

Блоки (замыкания в Swift) должны быть намеренно оставлены пустыми!

Ответ 6

Хорошим способом анимировать размер ячейки является переопределение isSelected в самом наборе коллекции.

class CollectionViewCell: UICollectionViewCell {

    override var isHighlighted: Bool {
        didSet {
            if isHighlighted {
                UIView.animate(withDuration: 0.2, delay: 0, options: .curveEaseOut, animations: {
                    self.transform = CGAffineTransform(scaleX: 0.95, y: 0.95)
                }, completion: nil)
            } else {
                UIView.animate(withDuration: 0.2, delay: 0, options: .curveEaseOut, animations: {
                    self.transform = CGAffineTransform(scaleX: 1, y: 1)
                }, completion: nil)
            }
        }
    }

}

Ответ 7

Это сработало для меня.

    collectionView.performBatchUpdates({ () -> Void in
        let ctx = UICollectionViewFlowLayoutInvalidationContext()
        ctx.invalidateFlowLayoutDelegateMetrics = true
        self.collectionView!.collectionViewLayout.invalidateLayoutWithContext(ctx)
    }) { (_: Bool) -> Void in
    }

Ответ 8

Использование executeBatchUpdates не будет анимировать макет содержимого ячейки. Вместо этого вы можете использовать следующее:

    collectionView.collectionViewLayout.invalidateLayout()

    UIView.animate(
        withDuration: 0.4,
        delay: 0.0,
        usingSpringWithDamping: 1.0,
        initialSpringVelocity: 0.0,
        options: UIViewAnimationOptions(),
        animations: {
            self.collectionView.layoutIfNeeded()
        },
        completion: nil
    )

Это дает очень плавную анимацию.

Это похоже на ответ Игнатия Тремора, но анимация перехода не работает должным образом для меня.

См. https://github.com/cnoon/CollectionViewAnimations для полного решения.