Swift:Collection 中 UIControl 的 tvOS IBAction 永远不会被调用
Swift: tvOS IBAction for UIControl in Collection View cell never gets called
我知道这个问题已经被问过很多次了,但我仍在学习,我已经在 S.O 中尝试了所有可能的解决方案。而且我一次都没有运气。这就是问题所在:
- 我正在使用 Xcode 11 beta 3(希望这不是问题所在!)
- 我在视图控制器中有一个简单的 collection 视图
- 我在单元格内放置了一个 tvOS' TVPosterView - 它继承自 UIControl 并自行测试它的行为确实像一个按钮(IBAction 被调用)。
- 在collection视图上有我推送海报时的动画
- 海报视图有一个默认图像,我只是更改标题
- 我将一个 IBAction 从海报视图拖到 IBclass 中的单元格
- 除了 IBAction,collection 视图可以正常显示和滚动,更改海报的标题
- 如果我将 collection 视图委托给视图控制器,collectionView(_ collectionView: UICollection查看,didSelectItemAt indexPath: IndexPath) 确实被调用了。
代码如下:
视图控制器
import UIKit
import TVUIKit
class SecondViewController: UIViewController {
@IBOutlet weak var myView: UIView!
@IBOutlet weak var myCollection: MyCollection!
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
}
}
extension SecondViewController: UICollectionViewDataSource {
func numberOfSections(in collectionView: UICollectionView) -> Int {
return 1
}
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return 10
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "MyCell", for: indexPath) as! MyCell
cell.myPoster.title! = "Header " + String(indexPath.row + 1)
cell.myPoster.tag = indexPath.row + 1
cell.posterTapAction = { cell in
print("Header is: \(cell.myPoster.title!)")
}
return cell
}
}
extension SecondViewController: UICollectionViewDelegate {
func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
// This one works - but that's not what I am looking for
print("From didSelectItemAt indexPath: \(indexPath.item + 1)")
}
}
Collection 查看
import UIKit
class MyCollection: UICollectionView {
override func awakeFromNib() {
super.awakeFromNib()
}
override func layoutSubviews() {
super.layoutSubviews()
}
}
单元格
import UIKit
import TVUIKit
class MyCell: UICollectionViewCell {
var posterTapAction: ((MyCell) -> Void)?
@IBOutlet weak var myPoster: TVPosterView!
@IBAction func myAction(_ sender: TVPosterView) {
posterTapAction?(self)
print("Poster pressed \(sender.tag)")
}
}
知道我遗漏了什么吗?我很乐意在按下海报后设法打印一个虚拟字符串。
我也尝试过选择器和委托的解决方案,none 有效。所以,请让我们用 closures 专注于这个特定的解决方案。谢谢!
终于找到了。像往常一样,这是由于 tvOS 焦点。基本上,单元格必须不可聚焦,以便单元格内的 UIControl 元素(在我的例子中是 TVPosterView,但它可以是任何 UIControl)将成为焦点。这是骗人的,因为在图形上它确实看起来好像海报有焦点(可以稍微旋转海报)。
解决方法是在UICollectionViewDelegate
中添加collectionView(_:canFocusItemAt:)
extension SecondViewController: UICollectionViewDelegate {
func collectionView(_ collectionView: UICollectionView,
canFocusItemAt indexPath: IndexPath) -> Bool {
return false
}
func collectionView(_ collectionView: UICollectionView,
didSelectItemAt indexPath: IndexPath) {
// Now, thanks to the function above, this is disabled
print("From didSelectItemAt indexPath: \(indexPath.item + 1)")
}
}
我已经在这个问题的代码中测试过了,并且也添加到了我的项目中,终于成功了!
我知道这个问题已经被问过很多次了,但我仍在学习,我已经在 S.O 中尝试了所有可能的解决方案。而且我一次都没有运气。这就是问题所在:
- 我正在使用 Xcode 11 beta 3(希望这不是问题所在!)
- 我在视图控制器中有一个简单的 collection 视图
- 我在单元格内放置了一个 tvOS' TVPosterView - 它继承自 UIControl 并自行测试它的行为确实像一个按钮(IBAction 被调用)。
- 在collection视图上有我推送海报时的动画
- 海报视图有一个默认图像,我只是更改标题
- 我将一个 IBAction 从海报视图拖到 IBclass 中的单元格
- 除了 IBAction,collection 视图可以正常显示和滚动,更改海报的标题
- 如果我将 collection 视图委托给视图控制器,collectionView(_ collectionView: UICollection查看,didSelectItemAt indexPath: IndexPath) 确实被调用了。
代码如下:
视图控制器
import UIKit
import TVUIKit
class SecondViewController: UIViewController {
@IBOutlet weak var myView: UIView!
@IBOutlet weak var myCollection: MyCollection!
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
}
}
extension SecondViewController: UICollectionViewDataSource {
func numberOfSections(in collectionView: UICollectionView) -> Int {
return 1
}
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return 10
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "MyCell", for: indexPath) as! MyCell
cell.myPoster.title! = "Header " + String(indexPath.row + 1)
cell.myPoster.tag = indexPath.row + 1
cell.posterTapAction = { cell in
print("Header is: \(cell.myPoster.title!)")
}
return cell
}
}
extension SecondViewController: UICollectionViewDelegate {
func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
// This one works - but that's not what I am looking for
print("From didSelectItemAt indexPath: \(indexPath.item + 1)")
}
}
Collection 查看
import UIKit
class MyCollection: UICollectionView {
override func awakeFromNib() {
super.awakeFromNib()
}
override func layoutSubviews() {
super.layoutSubviews()
}
}
单元格
import UIKit
import TVUIKit
class MyCell: UICollectionViewCell {
var posterTapAction: ((MyCell) -> Void)?
@IBOutlet weak var myPoster: TVPosterView!
@IBAction func myAction(_ sender: TVPosterView) {
posterTapAction?(self)
print("Poster pressed \(sender.tag)")
}
}
知道我遗漏了什么吗?我很乐意在按下海报后设法打印一个虚拟字符串。
我也尝试过选择器和委托的解决方案,none 有效。所以,请让我们用 closures 专注于这个特定的解决方案。谢谢!
终于找到了。像往常一样,这是由于 tvOS 焦点。基本上,单元格必须不可聚焦,以便单元格内的 UIControl 元素(在我的例子中是 TVPosterView,但它可以是任何 UIControl)将成为焦点。这是骗人的,因为在图形上它确实看起来好像海报有焦点(可以稍微旋转海报)。
解决方法是在UICollectionViewDelegate
中添加collectionView(_:canFocusItemAt:)extension SecondViewController: UICollectionViewDelegate {
func collectionView(_ collectionView: UICollectionView,
canFocusItemAt indexPath: IndexPath) -> Bool {
return false
}
func collectionView(_ collectionView: UICollectionView,
didSelectItemAt indexPath: IndexPath) {
// Now, thanks to the function above, this is disabled
print("From didSelectItemAt indexPath: \(indexPath.item + 1)")
}
}
我已经在这个问题的代码中测试过了,并且也添加到了我的项目中,终于成功了!