美文网首页Unity
Unity 适配 iPhone X 的一种实现方法

Unity 适配 iPhone X 的一种实现方法

作者: 加菲教主 | 来源:发表于2018-01-31 08:22 被阅读0次

    我一边骂着苹果是专利流氓,对开发者还极其不友好,一边又得靠 iOS 这个平台养活自己。于是当他们出了个带刘海儿的鬼东西之后,我还是得想想怎么适配 GUI。在 UWA 上提问之后,有同行提供了一些思路(参见这里),再加上和朋友讨论,决定用本文描述的这种实现方法。

    注意:

    • 以下基于横屏的情况描述,但竖屏的情况也是类似的。
    • 以下实现基于 NGUI 插件,但我估计 UGUI、FairyGUI 等均可以类似的方式实现。

    基本原理

    苹果建议的安全区是这样的:


    其实就是需要比屏幕的外接矩形小一号的矩形(上图中浅绿色矩形),一些控件需要锚定到这个小一号的矩形上。

    在这个基础上,我需要做几件事:

    • 实现一个安全区控制器组件,配合 UIWidget 使用。运行时判断机型是否为 iPhone X 横屏,如果是,调整 UIWidget 的尺寸。
    • 基于这个组件,给拼 UI 的人(不论是策划、美术还是程序)设计一个操作流程,来修改已经做好的 UI prefab 和创建新的 UI prefab。
    • 在编辑器里能够快速的「假装」自己是 iPhone X 横屏,以便拼 UI 的人可以在某种程度上「所见即所得」的看到这些 UI 在 iPhone X 上的样子。

    运行时

    运行时的部分主要由两个组件(MonoBehaviour)组成:

    安全区管理器(Manager)

    • 既然是个管理器,Manager 这个类就只能有一个。不妨实现为 Unity 风格的单例(即在 Awake 时设置静态 Instance 字段的值为自身,在 OnDestroy 时设置 Instancenull)。这样,之后要说的 Controller 就可以从 Manager 这里获得其唯一实例了。
    • 这个类的主要工作,是根据当前平台、设备型号(SystemInfo.deviceModel)等信息来获得当前是否为 iPhone X 横屏(需要判断横屏的话, UnityEngine.Screen 类能胜任),或者是否是在「假装」iPhone X 横屏。这样便可以去配置文件里获得相应的安全区的尺寸和位置。
    • 这个部分的实现,可以是策略模式。其好处将在于,以后如果下一代 iPhone 或者什么别的设备又有了新的安全区设定,这个功能将很容易扩展。

    安全区控制器(Controller)

    • 这个类将要直接配合一个 UIRect 的子类对象来使用(如果是 UGUI 的话应该是配合一个 RectTransform)。
    • 其实现要在合适的时候(对 NGUI 来说就是 Start 时)将安全区的位置、尺寸信息从 Manager 处获取到,并设置到这个 UIRect 的锚点信息中(这个 UIRect 锚的对象是该界面的任何一个全屏 UIPanel 对象),从而改变其位置和尺寸。NGUI 中的 UIRect.SetAnchor 方法组有多个重载,可以根据需要调用。
    • 把需要配合安全区改变位置的控件,锚定在这个 Controller 上附带的 UIRect
      上,在运行时它们就会随着 UIRect 的变化而变化。
    • 将上述内容做在一个 Prefab 里,供拼 UI 的人使用。拼 UI 的人只需要将其拖到正在编辑的 UI Prefab 中,指定一个 UIPanel 就可以让它生效。(当然直接做个菜单项就更好了)

    编辑器

    很讽刺,反倒是编辑器当中需要做的事情比较多。

    简单的部分是,将上述内容做在一个 Prefab 里,供拼 UI 的人使用。拼 UI 的人只需要将其拖到正在编辑的 UI Prefab 中,指定一个 UIPanel 就可以让它生效。(当然直接做个菜单项就更好了)

    实现起来麻烦一点的,就是在编辑器里假装自己是 iPhone X

    • 准备一个开关,切换正常屏显模式(A)和 iPhone X 横屏模拟模式(B)。如果以后有其他安全区形式还可以扩展更多的模式。

    • 准备一个场景,用于 B 模式下显示一个 iPhone X 形状的遮罩(我是在这里得到的图)。因为它将只在编辑器中使用,因此我直接用 UGUI。注意适当设置其中的 Canvas 以便显示在最前。

    用于 B 模式的场景
    其中的Mask节点
    • 在切换到 B 模式的时候,首先强迫 Unity 的 Game 视图展示为一个和 iPhone X 等比例的范围,即 812:375。实现方法参见这里

    • 接下来利用 UnityEditor 的 API 以增量方式加载这个新场景,然后它就会显示在现有场景的前面,在其中编辑 UI Prefab 的时候,就在一定程度上所见即所得了。(EditorSceneManager 中的
      方法 OpenScene(scenePath, OpenSceneMode.Additive) 可以胜任这个工作)。

    • 恢复 A 模式的时候,将增量加载出来的场景关闭就是了。(用 EditorSceneManager 中的方法
      GetSceneByNameCloseScene 即可)

    陷阱和问题

    • 支持 UIAnchorUIAnchor 我理解是个比较过时的东西,能不用就尽量别用。如果一定要支持它,那么 Controller 的脚本执行顺序(Script execution order)需要调整到 UIAnchor 之前,即需要在 UIAnchor 起作用之前,设置好其锚定目标的位置和尺寸。注意,在导入 NGUI 插件时,UIAnchor 的执行顺序本来就不是 0。
    • Manager 的实例在哪儿:为了在编辑模式下能所见即所得地调整 UI,需要让 Manager 和 Controller 都在编辑模式下可执行,并且在制作 UI 的场景(比如游戏的启动场景)中预先保存挂上 Manager 脚本的节点。但这时候如果触发了编译,编译之后 Manager 的 Instance 就获取不到了,需要重新载入场景才能获取到。这个是不是有什么更优美的方式来解决?
    • 由于有上面这个问题,我觉得需要研究研究这类既能在编辑模式执行,又能在运行模式执行的脚本,如何写比较好了。

    相关文章

      网友评论

        本文标题:Unity 适配 iPhone X 的一种实现方法

        本文链接:https://www.haomeiwen.com/subject/cfxhzxtx.html