tvOS/Swift 3: 如何修复损坏的 UICollectionView 选择动画?
tvOS/Swift 3: How fix broken UICollectionView selection animation?
我已经将 UICollectionViewCell 子类化,这样视差效果就可以应用于整个单元格,而不仅仅是单元格中的图像。视差效果如我所愿,但它会破坏按钮,就像在选定单元格上按下远程按钮时发生的动画一样。
collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) 被调用,因为它应该是远程按钮,只是没有任何动画。
我想我必须制作动画,但不知道如何触发它,或者实际上不知道如何制作它。
这是我的 UICollectionViewCell:
class CollectionViewCellA: UICollectionViewCell {
@IBOutlet var image: UIImageView!
@IBOutlet var bkgImage: UIImageView!
@IBOutlet var title: UILabel!
override func didUpdateFocus(in context: UIFocusUpdateContext, with coordinator: UIFocusAnimationCoordinator) {
struct wrapper {
static let s_atvMotionEffect = UIAppleTVMotionEffectGroup()
}
coordinator.addCoordinatedAnimations( {
var scale : CGFloat = 0.0
if self.isFocused {
self.addMotionEffect(wrapper.s_atvMotionEffect)
self.layer.shadowOpacity = 0.75;
self.layer.shadowRadius = 32.0;
self.layer.shadowOffset = CGSize(width: 0, height: 16);
scale = 1.2
} else {
self.removeMotionEffect(wrapper.s_atvMotionEffect)
self.layer.shadowOpacity = 0.25;
self.layer.shadowRadius = 4.0;
self.layer.shadowOffset = CGSize(width: 0, height: 0);
scale = 1.0
}
let transform = CGAffineTransform(scaleX: scale, y: scale)
self.layer.setAffineTransform(transform)
},completion: nil)
}
}
这是 UICollectionView 所在的 UIViewController:
class HomeVC: UIViewController, UICollectionViewDelegate, UICollectionViewDataSource, UICollectionViewDelegateFlowLayout {
@IBOutlet var freeContentCV: UICollectionView!
@IBOutlet var collectionViewB: UICollectionView!
@IBOutlet var scrollView: UIScrollView!
@IBOutlet var mainImage: UIImageView!
override func viewDidLoad() {
super.viewDidLoad()
freeContentCV.delegate = self
collectionViewB.delegate = self
freeContentCV.dataSource = self
collectionViewB.dataSource = self
}
override func viewDidLayoutSubviews() {
self.scrollView!.contentSize = CGSize(width: 1920, height: 2500)
}
override func didUpdateFocus(in context: UIFocusUpdateContext, with coordinator: UIFocusAnimationCoordinator) {
//print(UIScreen.main.focusedView)
}
// Collection View Methods
func numberOfSections(in collectionView: UICollectionView) -> Int {
return 1
}
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
if collectionView == self.freeContentCV{
return 10
}
return 10
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
if collectionView == self.freeContentCV {
let cellA = collectionView.dequeueReusableCell(withReuseIdentifier: "CellA", for: indexPath) as! CollectionViewCellA
cellA.bkgImage.image = UIImage(named: "vincent")
cellA.title.text = "TITLE"
return cellA
}
let cellB = collectionView.dequeueReusableCell(withReuseIdentifier: "CellB", for: indexPath) as! CollectionViewCellA
cellB.image.image = UIImage(named: "vincent")
cellB.title.text = "TITLE"
return cellB
}
func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
// What goes here to trigger an animation, if anything?
}
}
我假设 didSelectItemAt 函数是我必须触发按钮动画的地方,但我不知道如何访问 UICollectionViewCell 来为它设置动画,或者即使这可以通过我的安排实现。在我的 iOS/tvOS 理解的边缘,所以我不确定要问的正确问题。
我查看了很多资源,但尚未找到任何关于此问题的讨论。
收到的任何想法。
今天早上重新破解这个问题后,下面是有效的方法。
在 UICollectionViewCell 中
class CollectionViewCellA: UICollectionViewCell {
@IBOutlet var image: UIImageView!
@IBOutlet var bkgImage: UIImageView!
@IBOutlet var title: UILabel!
var selectTrans: UIFocusAnimationCoordinator?
var scale : CGFloat = 0.0
override func didUpdateFocus(in context: UIFocusUpdateContext, with coordinator: UIFocusAnimationCoordinator) {
struct wrapper {
static let s_atvMotionEffect = UIAppleTVMotionEffectGroup()
}
coordinator.addCoordinatedAnimations( {
if self.isFocused {
self.addMotionEffect(wrapper.s_atvMotionEffect)
self.layer.shadowOpacity = 0.75;
self.layer.shadowRadius = 10.0;
self.layer.shadowOffset = CGSize(width: 0, height: 5);
self.scale = 1.2
let transform = CGAffineTransform(scaleX: self.scale, y: self.scale)
self.layer.setAffineTransform(transform)
} else {
self.removeMotionEffect(wrapper.s_atvMotionEffect)
self.layer.shadowOpacity = 0.25;
self.layer.shadowRadius = 4.0;
self.layer.shadowOffset = CGSize(width: 0, height: 0);
self.scale = 1.0
let transform = CGAffineTransform(scaleX: self.scale, y: self.scale)
self.layer.setAffineTransform(transform)
}
},completion: nil)
}
func startSelectAnimation() {
scale = 1.1
let transform = CGAffineTransform(scaleX: scale, y: scale)
self.layer.setAffineTransform(transform)
perform(#selector(middleAnimation), with: nil, afterDelay: 0.08)
}
func middleAnimation() {
scale = 0.95
let transform = CGAffineTransform(scaleX: scale, y: scale)
self.layer.setAffineTransform(transform)
perform(#selector(endSelectAnimation), with: nil, afterDelay: 0.1)
}
func endSelectAnimation(){
scale = 1.2
let transform = CGAffineTransform(scaleX: scale, y: scale)
self.layer.setAffineTransform(transform)
}
}
在ViewController
func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
// We have to provide animation, so get the cell and do call to animation
let selectedCell = collectionView.cellForItem(at: indexPath) as! CollectionViewCellA
selectedCell.startSelectAnimation()
if collectionView == self.freeContentCV {
performSegue(withIdentifier: "ShowVideoDetail", sender: self)
}
}
动画有点笨拙,但当它触发 segue 时,抖动并不是那么明显。
我已经将 UICollectionViewCell 子类化,这样视差效果就可以应用于整个单元格,而不仅仅是单元格中的图像。视差效果如我所愿,但它会破坏按钮,就像在选定单元格上按下远程按钮时发生的动画一样。
collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) 被调用,因为它应该是远程按钮,只是没有任何动画。
我想我必须制作动画,但不知道如何触发它,或者实际上不知道如何制作它。
这是我的 UICollectionViewCell:
class CollectionViewCellA: UICollectionViewCell {
@IBOutlet var image: UIImageView!
@IBOutlet var bkgImage: UIImageView!
@IBOutlet var title: UILabel!
override func didUpdateFocus(in context: UIFocusUpdateContext, with coordinator: UIFocusAnimationCoordinator) {
struct wrapper {
static let s_atvMotionEffect = UIAppleTVMotionEffectGroup()
}
coordinator.addCoordinatedAnimations( {
var scale : CGFloat = 0.0
if self.isFocused {
self.addMotionEffect(wrapper.s_atvMotionEffect)
self.layer.shadowOpacity = 0.75;
self.layer.shadowRadius = 32.0;
self.layer.shadowOffset = CGSize(width: 0, height: 16);
scale = 1.2
} else {
self.removeMotionEffect(wrapper.s_atvMotionEffect)
self.layer.shadowOpacity = 0.25;
self.layer.shadowRadius = 4.0;
self.layer.shadowOffset = CGSize(width: 0, height: 0);
scale = 1.0
}
let transform = CGAffineTransform(scaleX: scale, y: scale)
self.layer.setAffineTransform(transform)
},completion: nil)
}
}
这是 UICollectionView 所在的 UIViewController:
class HomeVC: UIViewController, UICollectionViewDelegate, UICollectionViewDataSource, UICollectionViewDelegateFlowLayout {
@IBOutlet var freeContentCV: UICollectionView!
@IBOutlet var collectionViewB: UICollectionView!
@IBOutlet var scrollView: UIScrollView!
@IBOutlet var mainImage: UIImageView!
override func viewDidLoad() {
super.viewDidLoad()
freeContentCV.delegate = self
collectionViewB.delegate = self
freeContentCV.dataSource = self
collectionViewB.dataSource = self
}
override func viewDidLayoutSubviews() {
self.scrollView!.contentSize = CGSize(width: 1920, height: 2500)
}
override func didUpdateFocus(in context: UIFocusUpdateContext, with coordinator: UIFocusAnimationCoordinator) {
//print(UIScreen.main.focusedView)
}
// Collection View Methods
func numberOfSections(in collectionView: UICollectionView) -> Int {
return 1
}
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
if collectionView == self.freeContentCV{
return 10
}
return 10
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
if collectionView == self.freeContentCV {
let cellA = collectionView.dequeueReusableCell(withReuseIdentifier: "CellA", for: indexPath) as! CollectionViewCellA
cellA.bkgImage.image = UIImage(named: "vincent")
cellA.title.text = "TITLE"
return cellA
}
let cellB = collectionView.dequeueReusableCell(withReuseIdentifier: "CellB", for: indexPath) as! CollectionViewCellA
cellB.image.image = UIImage(named: "vincent")
cellB.title.text = "TITLE"
return cellB
}
func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
// What goes here to trigger an animation, if anything?
}
}
我假设 didSelectItemAt 函数是我必须触发按钮动画的地方,但我不知道如何访问 UICollectionViewCell 来为它设置动画,或者即使这可以通过我的安排实现。在我的 iOS/tvOS 理解的边缘,所以我不确定要问的正确问题。
我查看了很多资源,但尚未找到任何关于此问题的讨论。
收到的任何想法。
今天早上重新破解这个问题后,下面是有效的方法。
在 UICollectionViewCell 中
class CollectionViewCellA: UICollectionViewCell {
@IBOutlet var image: UIImageView!
@IBOutlet var bkgImage: UIImageView!
@IBOutlet var title: UILabel!
var selectTrans: UIFocusAnimationCoordinator?
var scale : CGFloat = 0.0
override func didUpdateFocus(in context: UIFocusUpdateContext, with coordinator: UIFocusAnimationCoordinator) {
struct wrapper {
static let s_atvMotionEffect = UIAppleTVMotionEffectGroup()
}
coordinator.addCoordinatedAnimations( {
if self.isFocused {
self.addMotionEffect(wrapper.s_atvMotionEffect)
self.layer.shadowOpacity = 0.75;
self.layer.shadowRadius = 10.0;
self.layer.shadowOffset = CGSize(width: 0, height: 5);
self.scale = 1.2
let transform = CGAffineTransform(scaleX: self.scale, y: self.scale)
self.layer.setAffineTransform(transform)
} else {
self.removeMotionEffect(wrapper.s_atvMotionEffect)
self.layer.shadowOpacity = 0.25;
self.layer.shadowRadius = 4.0;
self.layer.shadowOffset = CGSize(width: 0, height: 0);
self.scale = 1.0
let transform = CGAffineTransform(scaleX: self.scale, y: self.scale)
self.layer.setAffineTransform(transform)
}
},completion: nil)
}
func startSelectAnimation() {
scale = 1.1
let transform = CGAffineTransform(scaleX: scale, y: scale)
self.layer.setAffineTransform(transform)
perform(#selector(middleAnimation), with: nil, afterDelay: 0.08)
}
func middleAnimation() {
scale = 0.95
let transform = CGAffineTransform(scaleX: scale, y: scale)
self.layer.setAffineTransform(transform)
perform(#selector(endSelectAnimation), with: nil, afterDelay: 0.1)
}
func endSelectAnimation(){
scale = 1.2
let transform = CGAffineTransform(scaleX: scale, y: scale)
self.layer.setAffineTransform(transform)
}
}
在ViewController
func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
// We have to provide animation, so get the cell and do call to animation
let selectedCell = collectionView.cellForItem(at: indexPath) as! CollectionViewCellA
selectedCell.startSelectAnimation()
if collectionView == self.freeContentCV {
performSegue(withIdentifier: "ShowVideoDetail", sender: self)
}
}
动画有点笨拙,但当它触发 segue 时,抖动并不是那么明显。