[关闭]
@Rays 2017-11-15T10:15:45.000000Z 字数 4724 阅读 2645

如何控制iPhone X的Home指示键

语言开发


摘要: iPhone X给出了一个称为“Home指示键”的新特性,替代了物理Home键。这导致了使用上的差异,并对App开发提出了新的挑战。尽管大部分App无需担心,Apple会自动调整,但是开发人员还是应该了解相关API的特性及考量。

作者: Jordan Morgan

正文:

本文最初发布于Medium网站,原作者Jordan Morgan。本文经授权由InfoQ中文站翻译并分享。

我们每个人都应该听说了,Apple发布了iPhone X。随之而来的,是新推出的自动隐藏在手机屏幕底部的一个横条,官方称其为“Home指示键”。它唤起了用户对iPhone物理Home按钮的怀旧感。

对于消费者而言,这意味着在硬件和软件上的一个新奇迹,每次预定时需要投入更多的钱。但是对于很多开发人员而言,这意味着应如何去处理这个鬼东西。感谢上帝,答案非常简单。

本周,我们将介绍Apple已为我们给出了的Home指示键处理技术。

首先

并非每天都有新视频随硬件发布,但这恰恰是在此之后发生的事情:


在Twitter上查看图片

在“为iPhone X设计”的活动中,苹果的终身设计大师Mike Stern制定了一些基本规则。一碗水端平,在使用下面的新功能之前,希望你首先踩住刹车,看一下自身情况是否符合如下规定:

原文太长了,读不下去了!。反正Apple的意思就是在大部分情况下,我们都不要去骚扰那个可怜的Home指示键。

但是,本文介绍的正是其中的特例。

添加UIViewController

无论你是否喜欢根据每个控制器处理状态条,或者你纯粹是对Home指示键看不惯,Apple依然继续延续了因人而异的决策方式,而非选择去满足大众的设计。

隐藏Home Indicator的机制在本质上类似于状态条的处理:

  1. class ViewController: UIViewController
  2. {
  3. override func prefersHomeIndicatorAutoHidden() -> Bool
  4. {
  5. return true
  6. }
  7. }

我们在前面说过,此类场景是个别情况,因此如上实现缺省返回False值。但在文档中特别提及:

系统也考虑到了个人喜好,返回YES并非确保会去隐藏Home指示键。

文档中似乎并未提及,为什么或是什么时候UIKit不会遵循开发人员选择的偏好。文档认为,在Apple看来是最好的方式,它就会强制执行这一方式,无论程序返回的布尔值是什么。对此,肯定会有一些Stack Overflow帖子讨论这一问题。

此外,这一问题看上去十分明显,但可能是开始产生混淆的一个源头。值得特别注意的是,函数名结尾是autoHidden但是并未隐藏,其实只能说明函数返回True意味着UIKit只有在其准备好之后才会去隐藏Home指示键(正常情况下,如果控制器在数秒时间范围内并未接受到任何触摸事件),而不是立刻去隐藏。

UIKit的信号处理

我们看一下类似的状态条API。我们并不能仅是重写API,或是将API赋予一个有条件地控制重写函数的变量。我们可使用另一个新的添加到视图控制器的稳健函数族,setNeedsSomethingDone

  1. class ViewController: UIViewController
  2. {
  3. var shouldHideHomeIndicator = false
  4. override func prefersHomeIndicatorAutoHidden() -> Bool
  5. {
  6. return shouldHideHomeIndicator
  7. }
  8. override func viewDidAppear(_ animated: Bool)
  9. {
  10. super.viewDidAppear(animated)
  11. self.shouldHideHomeIndicator = true
  12. self.setNeedsUpdateOfHomeIndicatorAutoHidden()
  13. }
  14. }

它可用于直接分配(Pass Through)函数,因为它只是向UIKit发出信号,告知UIKit我们已经更改了前面选择用于Home指示键可见性的值。不同于状态栏的是,从技术上看它并非立刻产生动画效果(Animatable),因为UIKit是根据自身约定执行隐藏动作。所以,下面的代码并不会产生任何效果:

  1. override func viewDidAppear(_ animated: Bool)
  2. {
  3. super.viewDidAppear(animated)
  4. DispatchQueue.main.asyncAfter(deadline: .now() + 1.0) {
  5. self.shouldHideHomeIndicator = true
  6. UIView.animate(withDuration: 1, animations: {
  7. self.setNeedsUpdateOfHomeIndicatorAutoHidden()
  8. })
  9. }
  10. }

setNeedsUpdateOfHomeIndicatorAutoHidden()的简单的赋值和调用,将轻微修改组件的Alpha属性产生淡入淡出。无论该组件是否位于一个动画块(Animation Block)中。

Container控制器

视图控制器(View Controller)的另一个新添加特性,是告知UIKit一个子视图控制器是否应该控制Home指示键可见性的机制。如果你具有足够丰富的iOS经验,你可能会驾驭容器视图控制器,更好地提升抽象和封装模式。

其中包含的这些控制器可能会发现自身已经近乎屏幕底部。如果是这样,你可能想要抛开Home指示键做事。一个简单的重写就可解决这个问题。它会返回被掩盖(Obscure)的实例,或是去掩盖一些实例。代码如下:

  1. override func childViewControllerForHomeIndicatorAutoHidden() -> UIViewController?
  2. {
  3. return myChildController
  4. }

如果你已经指定了子控制器去标识可见性,那么重写我们前面所讨论的函数的担子现在落在了子控制器身上:

  1. class MyChildViewController: UIViewController
  2. {
  3. override func prefersHomeIndicatorAutoHidden() -> Bool
  4. {
  5. return true
  6. }
  7. }

函数的签名允许返回值为Nil。在此情况下,UIKit将查看当前做出决策的控制器。如果我们已经选择不重写函数,那么决策就是“显示Home指示键”。

我们也可以在运行时做出决策。UIKit将再次请求调用我们刚刚讨论过的直接分配(Pass Through)函数,通知框架应再一次查询prefersHomeIndicatorAutoHidden()

  1. override func childViewControllerForHomeIndicatorAutoHidden() -> UIViewController?
  2. {
  3. return myChildController
  4. }
  5. func initializeChildController()
  6. {
  7. myChildController = MyChildController()
  8. self.setNeedsUpdateOfHomeIndicatorAutoHidden()
  9. }

事情就是这样。

虽然我们可以将其看成一种更深思熟虑的过程,需要应用于日常iOS事件(即处理控制器)中,但是我们会发现API与现有的处理类似问题的UIKit函数几乎相同。

更新:读者问题解答

Fabian Kuenzel问:

新的Home指示键是否也会位于网站底部状态条之上?

解答详细列出于webkit.org中:

设计适用于iPhone X的Web网站

开箱即用,在新iPhone X的显示屏上,Safari可严丝合缝地显示已有的网站。

我已不再是Web开发的酷爱者了,但是这看上去是如下的元标签(meta tage)解决了自动插页问题:

  1. <meta name='viewport' content='initial-scale=1, viewport-fit=auto'>

默认值是auto,即允许插页内容。我们也可以重置该值,设置整个屏幕的显示方式。如果喜欢使用全屏,有一个新的CSS函数constant(),允许使用预定义常量在考虑安全区域的情况下填充元素四周。这类似于iOS的safeAreaLayoutGuide API.

webkit.org的帖子给出了一个例子:

  1. .post {
  2. padding: 12px;
  3. padding-left: constant(safe-area-inset-left);
  4. padding-right: constant(safe-area-inset-right);
  5. }

Bogdan的观察更理性:

我不理解为什么Apple不是默认关闭Home指示键,或是至少给用户一个选择去关闭它。尽管这是一个吸引新用户使用iPhone的特性,但是最终(可能只需使用iPhone十分钟)每个用户将记住如何切换App,这时Home指示键就成为一个烦人和干扰使用的横条。我说得不对吗?

说得好!

正如iPhone X的“刘海”(notch)已经不仅仅是看上去那一块异形状槽,它已融入到手机的硬件中,并会成为iPhone的品牌辨识,我认为在软件上具有相似特性的就是Home Indicator。它是手机的DNA组成。此外,我打赌Apple认为它的存在将会引领用户体验。它避免了“等等,为什么现在不见了?”、“它何时显示?”、“它何时隐藏?”、“在显示它时是否可以回到主界面?”之类的问题。

也就是说,我完全同意你的看法,Home指示键持续出现在屏幕上是有些多余。但是我还没有用上iPhone X,因此在实际使用之前我不做任何评论。

Will Kampmann问:

你是否了解,对于游戏等全屏App,Home指示键的使用情况如何?它是否会像在正常iPhone中通知和控制中心中设置的那样,被两次滑动激活?

我知道有一个API可以重写该行为,但是Apple真的、真的、真的不希望开发人员这样做。那么它适用于哪些情况呢?当然是全屏游戏。下面给出在“用户接口指南”(Human Interface Guidelines)中对此的介绍:

很少的情况下,即游戏等沉浸式App,可能新需要用户定义屏幕边缘手势。这些手势要优先于系统定义的手势。第一次滑动调用App特定的手势,第二次滑动调用系统定义手势。

任一视图控制器的重写都是很简单的:

  1. override func preferredScreenEdgesDeferringSystemGestures() -> UIRectEdge {
  2. return .top
  3. }

总结

iPhone X需做特别考虑。

这对于iOS工程师而言是否只是轻描淡写,还是需要去维护和编码的另一个视图控制器?可能是两者的混合。如果我们熟悉软件开发的连续体系的话,那么我们就明白,新的API=时间流逝+新的生态系统。当前在智能手机领域,更切实的说法是:时间流逝+Apple的生态系统=新的硬件=新的API。

我们面对的是加长的iPhone,具有不同的显示分辨,并需要处理导航栏上的相机小点,以及底框附近的两点小横条。

下回分解。

查看英文原文: iPhone X: Dealing with Home Indicator

添加新批注
在作者公开此批注前,只有你和作者可见。
回复批注