-
一、被切断的小红点
(一)问题描述
3年前我负责导航栏设计的时候,在红点处理这块遇到一个很神奇的问题。
简单描述是这样:
A push B页面,在B页面导航栏右边部分渲染了一个红点,但在左滑退出时,B导航栏上的红点被裁断了。
刚开始我觉得很奇怪,业内也没有人反馈过这个问题,我还特意去看了美团app,发现他们也有这样的问题:
当然了,别人也有这样的问题,这并不是一个好消息,说明这反而不是一个简单的问题。
别人没处理,但我们需要处理。
(二)问题处理
debug的过程我在这里就不多说了,我直接公布原因和处理方案。
- 为什么导航栏会被裁断?
iOS11所有的UIBarButtonItem都是加载到新的_UIButtonBarStackView上的,而_UIButtonBarStackView默认在5.5英寸机型有20px,其余机型为16px的边距。
在pop转场时,实际是系统对导航栏做了一个快照snapshot,这个快照把左右两边都截去了20px。
- 怎么处理?
在介绍解决方案之前,我们先明确一下 UINavigationBar 的渲染结构, UINavigationBar 的渲染结果本质是MVC作用的,其大致结构可以抽象如下:
- NavigationBar
- ContentView
- ContentItem
其中contentView担当的是View的角色,ContentItem担当的是Model的角色,Controller由NavigationController来承担,这里我们重点看contentView和ContentItem。
所有我们操作的非直接加到 NavigationBar 上的元素,都是通过设置 ContentItem ,然后由 ContentItem 驱动渲染到 ContentView 上的。
比如:self.title / self.navigationItem.titleView 。
好的,接下来我们要介绍的重点是:pop时生成的快照snapshot,其实是对 ContentView 的截图,如果我们把一个视图AAA主动的加到NavigationBar上,在pop时生成的快照是不会把AAA包含进去的。
所以解决方案就很清楚了:
我们把红点主动加到 NavigationBar 上,在willDisappear移出,在willAppear时添加上即可。
二、错乱的导航栏
(一)问题描述
这也是一个很麻烦的问题,我们都知道,每个页面有自己页面设置的导航栏,每个导航栏自己设置NavigationItem更新UI。
但这里遇到的一个问题是:导航栏的MVC机制失效了。
具体表现是:
A push B页面之后,在 B页面执行pop返回A页面之后,A页面的导航栏展示的还是B页面设置的。
(二)问题处理
我们都知道系统会在pop/push转场后根据NavigationItem去更新NavigationBar的视图,
我最初尝试过主动重新设置页面A的navigationItem,结果发现并没有效果。
那这就说明一个情况:在该情况下,A页面导航栏的MVC已经失效了,model和view并不是配对的了。
苹果写出bug,就需要我们来修bug了,我们要手动把导航视图进行修正,那怎么处理?
递归遍历NavigationBar里异常的View,全部remove掉
主动构建一个A页面需要的导航栏视图,贴到NavigationBar上