写点什么

如何控制 iPhone X 的 Home Indicator

2017 年 11 月 16 日

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

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

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

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

首先

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


在 Twitter 上查看图片

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

  • 尽量避免在 Home 指示键附近做交互控制,尤其是通过手势识别驱动的控制。
  • 不能隐藏 Home 指示键,也不能在四周做装饰,或是尝试去更改其外观。这些规则同样适用于位于 iPhone 顶部的相机面板(Bezel)
  • 通常除非观看体验(即视频、照片幻灯放映等)很差,否则通常不应隐藏 Home 指示键。

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

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

添加 UIViewController

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

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

复制代码
class ViewController: UIViewController
{
override func prefersHomeIndicatorAutoHidden() -> Bool
{
return true
}
}

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

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

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

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

UIKit 的信号处理

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

复制代码
class ViewController: UIViewController
{
var shouldHideHomeIndicator = false
override func prefersHomeIndicatorAutoHidden() -> Bool
{
return shouldHideHomeIndicator
}
override func viewDidAppear(_ animated: Bool)
{
super.viewDidAppear(animated)
self.shouldHideHomeIndicator = true
self.setNeedsUpdateOfHomeIndicatorAutoHidden()
}
}

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

复制代码
override func viewDidAppear(_ animated: Bool)
{
super.viewDidAppear(animated)
DispatchQueue.main.asyncAfter(deadline: .now() + 1.0) {
self.shouldHideHomeIndicator = true
UIView.animate(withDuration: 1, animations: {
self.setNeedsUpdateOfHomeIndicatorAutoHidden()
})
}
}

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

Container 控制器

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

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

复制代码
override func childViewControllerForHomeIndicatorAutoHidden() -> UIViewController?
{
return myChildController
}

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

复制代码
class MyChildViewController: UIViewController
{
override func prefersHomeIndicatorAutoHidden() -> Bool
{
return true
}
}

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

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

复制代码
override func childViewControllerForHomeIndicatorAutoHidden() -> UIViewController?
{
return myChildController
}
func initializeChildController()
{
myChildController = MyChildController()
self.setNeedsUpdateOfHomeIndicatorAutoHidden()
}

事情就是这样。

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

更新:读者问题解答

Fabian Kuenzel 问:

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

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

设计适用于 iPhone X 的 Web 网站

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

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

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

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

复制代码
.post {
padding: 12px;
padding-left: constant(safe-area-inset-left);
padding-right: constant(safe-area-inset-right);
}

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 特定的手势,第二次滑动调用系统定义手势。

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

复制代码
override func preferredScreenEdgesDeferringSystemGestures() -> UIRectEdge {
return .top
}

总结

iPhone X 需做特别考虑。

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

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

下回分解。

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

感谢覃云对本文的审校。

2017 年 11 月 16 日 16:553448
用户头像

发布了 367 篇内容, 共 88.9 次阅读, 收获喜欢 164 次。

关注

评论

发布
暂无评论
发现更多内容

三、基于 Docker-registry/Nexus3 搭建本地仓库

悟尘

Docker Kubernetes 容器 k8s Compose

我认为“写作平台”还缺少读者

小天同学

产品 反馈 写作平台 建议

程序员陪娃漫画系列——排队问题

孙苏勇

程序员 生活 程序员人生 陪伴 漫画

redis数据结构介绍二-第二部分 跳表

Nick

redis 源码 数据结构 源码分析 算法

回"疫"录(6):致敬最美逆行者

小天同学

疫情 回忆录 现实纪录 纪实 创新突破

多人实时互动之各WebRTC流媒体服务器比较

音视频专家-李超

WebRTC 在线教育 音视频会议 mediasoup janus

最通俗易懂的H264基本原理

音视频专家-李超

音视频 WebRTC ffmpeg 音视频会议 H264

Java并发编程系列——Fork-Join

孙苏勇

Java Java并发 并发编程 线程

web集群架构

桥哥技术之路

初入响应式编程(下)

CD826

spring 微服务 响应式编程 reactor

西江月·记游(一)

轩辕御龙

菩萨蛮·记游(二)

轩辕御龙

Make Tmux Great Again

ccx

tmux

四、Docker 网络原理、分类及容器互联配置

悟尘

Docker Kubernetes 容器 k8s Compose

从翻译到本地化:我在Airbnb做本地化经理的经历

葛仲君

产品 翻译 Airbnb 本地化 全球化

记游(四)

轩辕御龙

音视频已强势崛起,我们该如何快速入门音视频技术?

音视频专家-李超

音视频 WebRTC ffmpeg 在线教育 音视频会议

B站、Quora、InfoQ,哪个的阅读/播放量会先到10W+?

赵新龙

写作平台 B站 Quora

Istio 1.5:对开发人员有什么帮助?

麦叔

云原生 istio servicemesh

废掉一个人最好的办法是让他忙到没有时间思考

熊斌

程序员人生 职场 思考

如何学习区块链技术

Kaichao

比特币 区块链 以太坊

忆秦娥·记游(三)

轩辕御龙

没有永恒的技术,只有适合的技术

码闻强

技术 个人成长 职业规划

redis数据结构介绍三-第三部分 整数集合

Nick

redis 源码 数据结构 源码分析 算法

开发机直连Docker中的redis容器小案例

麦叔

redis Docker

工作时间都去哪儿了?

伯薇

效率 时间管理 个人提升 团队

Flink Weekly | 每周社区动态更新

Apache Flink

大数据 flink 流计算 实时计算 大数据处理

Netty系列之源码解析(一)

猿灯塔

Netty

一、Docker基础入门及架构介绍

悟尘

Docker Kubernetes 容器 k8s Compose

二、基于 Dockerfile 构建并运行镜像

悟尘

Docker Kubernetes 容器 k8s Compose

广告与数据算法系列1.1.1: 什么是广告

黄崇远@数据虫巢

互联网 算法 广告

InfoQ 极客传媒开发者生态共创计划线上发布会

InfoQ 极客传媒开发者生态共创计划线上发布会

如何控制iPhone X的Home Indicator-InfoQ