使 UILabel 可聚焦和可点击 (tvOS)

Make UILabel focusable and tappable (tvOS)

我正在尝试实现 6 行高描述标签,我希望它是可聚焦的。理想情况下,这意味着扩展 UILabel class 以制作自定义组件。我尝试通过实施 canBecomeFocuseddidUpdateFocusInContext 但我的 UILabel 似乎没有得到任何关注。

我也尝试用 UIButton 替换 UILabel,但按钮并没有真正针对这类事情进行优化。这也意味着我需要将 buttonType 的焦点从自定义更改为普通......而 buttonType 似乎是只读 属性.

实际上,我希望 Apple 在 Apple TV Movies 应用程序中实现完全相同的文本标签。对于电影描述,他们有一个显示几行文本的文本标签和一个 "more"。聚焦时,它看起来像一个按钮(周围有阴影)并改变了背景颜色。点击时 - 它会打开一个包含整个电影描述的模式 window。

有什么建议吗?或者也许有人已经为 tvOS 实现了这个自定义控件?或者更好的情况 - Apple 有一个组件可以执行此操作,但我遗漏了一些东西。

P.S:欢迎Swift解决方案:)

好的,回答我自己的问题:)

所以看起来有些视图 "focusable" 在 tvOS 上开箱即用,而其他视图必须按照指示才能这样做。

我最终使用了 UITextView,它有一个 selectable 属性,但默认情况下如果不是这些可聚焦视图之一。必须禁用 TextView 的编辑以使其看起来像 UILabel。此外,目前存在一个错误,它会阻止您使用 Interface Builder 中的 selectable 属性 但可以从代码中使用。

当然,canBecomeFocused()didUpdateFocusInContext也必须实施。您还需要传递 UIViewController 因为 UITextView 无法呈现模式视图控制器。下面是我最终创建的。

class FocusableText: UITextView {

    var data: String?
    var parentView: UIViewController?

    override func awakeFromNib() {
        super.awakeFromNib()
        let tap = UITapGestureRecognizer(target: self, action: "tapped:")
        tap.allowedPressTypes = [NSNumber(integer: UIPressType.Select.rawValue)]
        self.addGestureRecognizer(tap)
    }

    func tapped(gesture: UITapGestureRecognizer) {
        let storyboard = UIStoryboard(name: "Main", bundle: nil)
        if let descriptionView = storyboard.instantiateViewControllerWithIdentifier("descriptionView") as? DescriptionViewController {
            if let view = parentView {
                if let show = show {
                    descriptionView.descriptionText = self.data
                    view.modalPresentationStyle = UIModalPresentationStyle.OverFullScreen
                    view.presentViewController(descriptionView, animated: true, completion: nil)
                }
            }
        }
    }

    override func canBecomeFocused() -> Bool {
        return true
    }

    override func didUpdateFocusInContext(context: UIFocusUpdateContext, withAnimationCoordinator coordinator: UIFocusAnimationCoordinator) {

        if context.nextFocusedView == self {
            coordinator.addCoordinatedAnimations({ () -> Void in
                self.layer.backgroundColor = UIColor.blackColor().colorWithAlphaComponent(0.2).CGColor
            }, completion: nil)
        } else if context.previouslyFocusedView == self {
            coordinator.addCoordinatedAnimations({ () -> Void in
                self.layer.backgroundColor = UIColor.clearColor().CGColor
            }, completion: nil)
        }
    }

}

使用只有一个单元格的集合视图,并在焦点移动到单元格时在 didUpdateFocusInContext 中添加变换到单元格并更改单元格背景颜色。

override func didUpdateFocusInContext(context: UIFocusUpdateContext, withAnimationCoordinator coordinator: UIFocusAnimationCoordinator) {
    coordinator.addCoordinatedAnimations({
        if self.focused {
            self.transform = CGAffineTransformMakeScale(1.01, 1.01)
            self.backgroundColor = UIColor.whiteColor()
            self.textLabel.textColor = .blackColor()
        }
        else {
            self.transform = CGAffineTransformMakeScale(1, 1)
            self.backgroundColor = UIColor.clearColor()
            self.textLabel.textColor = .whiteColor()
        }
        }, completion: nil)
}

如果您像 iTunes 一样使用图像作为背景并将其用于单元格后面的视觉效果视图,您可以尝试提取图像的颜色。

您还可以对视频控制器中的 collectionView 应用变换,使其看起来像处于焦点状态

您可以使用系统按钮,将故事板中的背景图片设置为包含您想要的颜色的图片

关于使 UILabel 可聚焦:

class MyLabel: UILabel {

    override var canBecomeFocused: Bool {
        return true
    }

    override func didUpdateFocus(in context: UIFocusUpdateContext, with coordinator: UIFocusAnimationCoordinator) {
        super.didUpdateFocus(in: context, with: coordinator)

        backgroundColor = context.nextFocusedView == self ? .blue:.red

    }
}

重要!!! 如苹果开发者门户网站所述:

这个 属性 的值为 true 如果视图可以成为焦点;否则为假。

默认情况下,此 属性 的值为 false。 属性 通知焦点引擎视图是否能够被聚焦。有时即使视图 returns 为真,视图也可能由于以下原因而无法聚焦:

  • 视图已隐藏。

  • 视图的 alpha 设置为 0。

  • 视图已将 userInteractionEnabled 设置为 false。

  • 视图当前不在视图层次结构中。