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