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


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

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

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

8 58

8 ответов:

[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 метод.

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

// 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];

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

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

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

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

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

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

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

при вызове и пустом вызове performBathUpdates представление анимируется автоматически.

- (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) {

    }];
}

Я имел успех анимации изменений с помощью -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];

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

Свифт

    collectionView.performBatchUpdates({}){}

Obj-C

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

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

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

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)
            }
        }
    }

}

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

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

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

    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 для полного решения.