如何使用Hero Animation实现iOS Collection View单元格动画?如何制作门开合/滑入效果?
嘿,我来帮你搞定这两个Collection View单元格动画的问题!下面分两部分详细说明,代码都是Swift实现的,直接就能用~
使用Hero Animation实现Collection View单元格动画
Hero是个超好用的iOS动画库,能轻松实现单元格到详情页的过渡动画,步骤很清晰:
1. 先安装Hero
你可以用Swift Package Manager或者CocoaPods安装:
- Swift Package Manager:在Xcode里添加依赖,URL填
https://github.com/HeroTransitions/Hero.git - CocoaPods:在Podfile里加
pod 'Hero',然后pod install
2. 配置Collection View单元格
给每个单元格设置唯一的heroID,这样Hero才能识别要过渡的元素:
class CustomCollectionViewCell: UICollectionViewCell { override func awakeFromNib() { super.awakeFromNib() // 也可以在cellForItemAt方法里根据indexPath设置 self.hero.id = "cell_\(tag)" } }
3. 触发过渡动画
在Collection View的didSelectItemAt方法里,跳转到详情页时启用Hero过渡:
func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) { let detailVC = DetailViewController() // 给详情页里对应的目标视图设置和单元格相同的heroID detailVC.targetContentView.hero.id = "cell_\(indexPath.item)" // 开启Hero动画支持 detailVC.hero.isEnabled = true self.hero.isEnabled = true // 用push或present方式跳转,动画会自动生效 navigationController?.pushViewController(detailVC, animated: true) }
小提示
- 如果想自定义过渡样式,比如缩放+淡入,可以给元素设置
hero.modifiers:cell.hero.modifiers = [.scale(0.8), .fade] - 一定要保证过渡前后的元素
heroID完全匹配,否则动画会失效
实现门开合/左右滑入的Collection View单元格动画
这种自定义动画不需要第三方库,用UIKit自带的动画API就能实现,分两种常用场景:
场景1:单元格滚动进入视图时的动画
利用UICollectionViewDelegate的willDisplay方法,在单元格即将显示时添加动画:
左右滑入效果
func collectionView(_ collectionView: UICollectionView, willDisplay cell: UICollectionViewCell, forItemAt indexPath: IndexPath) { // 初始状态:单元格从右侧偏移到屏幕外,透明度为0 cell.transform = CGAffineTransform(translationX: UIScreen.main.bounds.width, y: 0) cell.alpha = 0 // 执行动画到正常状态,给每个单元格加一点延迟,营造瀑布流效果 UIView.animate(withDuration: 0.5, delay: 0.1 * Double(indexPath.item), options: .curveEaseOut) { cell.transform = .identity cell.alpha = 1 } }
门开合效果(绕右侧轴打开)
这种效果需要用到3D变换,给单元格添加透视感:
func collectionView(_ collectionView: UICollectionView, willDisplay cell: UICollectionViewCell, forItemAt indexPath: IndexPath) { // 设置锚点为右侧中心,让单元格绕右侧边缘旋转 cell.layer.anchorPoint = CGPoint(x: 1, y: 0.5) // 重置frame,避免锚点改变导致位置偏移 cell.frame = collectionView.frameForItem(at: indexPath)! // 初始状态:绕Y轴旋转90度(完全关闭),加上透视效果 var transform = CATransform3DIdentity transform.m34 = -1 / 500 // 透视系数,数值越小透视感越强 transform = CATransform3DRotate(transform, .pi/2, 0, 1, 0) cell.layer.transform = transform cell.alpha = 0 // 执行打开动画 UIView.animate(withDuration: 0.6, delay: 0.1 * Double(indexPath.item), options: .curveEaseInOut) { cell.layer.transform = CATransform3DIdentity cell.alpha = 1 } }
场景2:单元格选中时的门开合动画
如果是点击单元格时触发门开合效果,直接在didSelectItemAt里添加动画:
func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) { guard let cell = collectionView.cellForItem(at: indexPath) else { return } // 构造门打开的3D变换 var openTransform = CATransform3DIdentity openTransform.m34 = -1 / 500 openTransform = CATransform3DRotate(openTransform, .pi/2, 0, 1, 0) // 执行打开动画,结束后可以做跳转或关闭动画 UIView.animate(withDuration: 0.4) { cell.layer.transform = openTransform } completion: { _ in UIView.animate(withDuration: 0.4) { cell.layer.transform = CATransform3DIdentity } } }
关键注意事项
因为Collection View单元格是复用的,一定要在prepareForReuse里重置动画状态,避免滚动回来时出现异常:
class CustomCollectionViewCell: UICollectionViewCell { override func prepareForReuse() { super.prepareForReuse() transform = .identity layer.transform = CATransform3DIdentity alpha = 1 } }
内容的提问来源于stack exchange,提问作者Pramod More
相关产品推荐
相关产品推荐

