威立山

记录心路历程

0%

TVOS开发技巧

写在前面的话

之前一直觉得Apple TV 是个神奇的东西,迷一样的事物。国内基本见不到它的影子,而公司要做一个Apple TV app,作为一名”资深”iOS开发者,怎么能不兴奋呢😝
在使用Apple TV之后,感觉真的比国内安卓系统的智能电视要惊艳很多,遥控器都那么与众不同!操作方便,也赏心悦目;缺点是不能看各个电视频道

前期调研

  • 相关资料很少,国内基本没有啥资料,只能看英文资料啦!推荐一本书籍《tvOS Apprentice》入门
  • 使用Swift进行开发,国外资料基本都用Swift写,赶紧上船…

讲点有趣的

UIView的focus特效

  • 在电视屏幕上你看到App里展示的界面,大部分都是UIImageView呈现的,图片比文字更能吸引眼球。
    ImageView Focus
    看到没有,但你用手指在遥控器触摸区打转时,获得焦点的图片会被放大,随手指旋转并带有眩光的视觉!这样的效果,只需设置UIImageView的自带属性:adjustsImageWhenAncestorFocused即可,真棒!!!

  • UIView 有个属性canBecomeFocused可以设置是否能获得焦点状态,设置为true,然后重写didUpdateFocus()方法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
override func didUpdateFocus(in context: UIFocusUpdateContext, with coordinator: UIFocusAnimationCoordinator) {

if context.nextFocusedView == self { // 获得焦点
self.transform = CGAffineTransform(scaleX: 1.1, y: 1.1)
self.layer.shadowColor = UIColor.black.alpha(0.36).cgColor
self.layer.shadowOffset = CGSize(width: 0, height: 30)
//设置阴影,模糊效果的半径
self.layer.shadowRadius = 50
self.layer.shadowOpacity = 1.0
}else{ //失去焦点
self.transform = CGAffineTransform.identity
self.layer.shadowOpacity = 0.0
}
}

下面再看一个有意思的
表情

UIImageView的animationImages可以设置一组图片,然后让图片动起来~
可是当你把一组表情图片设置给animationImages,ImageView获得焦点时,表情并没有动啊! 解决方法:将UIImageView加到一个UIView上,当view获得焦点时,view调整transformscale,并让imageView开始startAnimating;失去焦点时,将view的transform还原,imageViewstopAnimating

如何控制焦点

Focus Engine(焦点引擎)

  • 我们可以将Focus视为聚光灯,将用户的注意力引导到屏幕上的特定元素。视图可以突出显示或聚焦,用户可以使用遥控器将焦点移动到应用的不同元素。
  • 当用户在遥控器的触摸面上滑动时,焦点引擎将朝着移动焦点的下一个视图的方向移动。如果它“看到”一个,它将Focus放在那里,如果没有看到它,它不会移动Focus。

例如:下面简单的3个按钮应用程序,当右上方的按钮处于焦点状态,用户向下滑动,想滑动到左下方按钮,因为焦点引擎看不到任何视图,所以Focus不会移动。
Focus示意图

这时候该 UIFocusGuide 登场了

UIFocusGuide

UIFocusGuide :是不可见的布局指导,可帮助Focus Engine知道将Focus移动到哪里。
我们把FocusGuide放到右下方,效果就像下图
FocusGuide

代码

首先,我们添加焦点指南的视图。

1
2
3
4
5
6
7
8
9
// Create the Focus Guide and add it to the view
var focusGuide = UIFocusGuide()
view.addLayoutGuide(focusGuide)

// Anchor the Focus Guide
focusGuide.widthAnchor.constraintEqualToAnchor(topRightButton.widthAnchor).active = true
focusGuide.heightAnchor.constraintEqualToAnchor(bottomLeftButton.heightAnchor).active = true
focusGuide.topAnchor.constraintEqualToAnchor(bottomLeftButton.topAnchor).active = true
focusGuide.leftAnchor.constraintEqualToAnchor(topRightButton.leftAnchor).active = true

然后,要使焦点指南直接聚焦到左下方的按钮,我们设置焦点指南的preferredFocusView属性; 这是“焦点指南”将引导焦点的view。

1
2
// Set preferred focus
focusGuide.preferredFocusedView = bottomLeftButton

调试

如果它们没有起作用,如何调试”焦点指南”呢?
苹果提供两种方式:

  1. Quick Look(快速查看)
  2. _whyIsThisViewNotFocusable

快速查看
Quick Look是一款用于调试Focus Engine和Focus Guide问题的可视化工具。
要使用它,你必须在方法中得到一个中断didUpdateFocusInContext(context, withAnimationCoordinator coordinator); 每次焦点被移动时都会被调用。然后,在Xcode左下角的Varibles视图中,突出显示context变量,然后单击底部的眼睛图标(或按空格键)。

whyIsThisViewNotFocusable
苹果还提供了(非常描述性地命名)LLDB命令,_whyIsThisViewNotFocusable称为另一个Focus调试工具。

要使用此命令,您需要在代码中的任何位置(或者甚至暂停它)中断中断,并_whyIsThisViewNotFocusable在LLDB命令行调试器中运行命令,如下所示:

1
[yourView _whyIsThisViewNotFocusable]

Swift命令是:

1
po yourView.performSelector(Selector("_whyIsThisViewNotFocusable"))

第三个方法Visual Focus Guides
Github地址

再吐槽一下

给图片加圆角

1
2
self.bgImageV.layer.masksToBounds = true
self.bgImageV.layer.cornerRadius = 10

TVOS上可没这么简单,这么做的后果是当图片在焦点状态时,图片放大的部分会被裁剪,这太坑了~😢

1
2
3
4
5
6
7
8
9
// Kingfisher库的生成圆角方法
///下载网络图片
let processor = RoundCornerImageProcessor(cornerRadius: 6)
ImageView.kf.setImage(with: model?.image, placeholder: nil, options: [.processor(processor)])

///本地图片
let image = UIImage.createImage(color: UIColor("#908F8F"), cornerRadius: 0, size: CGSize(width: 10, height: 10))
//fit 一定要是UIImageView的size大小
ImageView.image = image.kf.image(withRoundRadius: 6, fit: ImageView.size)

为啥在TVApp不能给UIImageView设置圆角呢?苹果怎么考虑的?可能是个bug!

参考

Debugging Focus in tvOS