iOS之优化UIPageViewController在深色模式下的翻页背景效果(干货)

优化初衷

1.用户反馈希望黑夜模式翻页不刺眼
2.我们自己也觉得很辣眼睛

效果图对比

优化前:

优化前的效果图

优化后:

优化后的效果图

前提

由于系统自带的翻页效果在深色模式下处理的不够友好,不管是深色还是浅色主题模式,他的翻页背景都是白色的。所以只能另辟蹊径,从doubleSided(UIPageViewController的一个属性)下手。设置doubleSided = YES,对PageViewController开启双面展示模式,也正因为如此,以下的两个方法都会触发两次:

- (nullable UIViewController *)pageViewController:(UIPageViewController *)pageViewController viewControllerBeforeViewController:(UIViewController *)viewController;

- (nullable UIViewController *)pageViewController:(UIPageViewController *)pageViewController viewControllerAfterViewController:(UIViewController *)viewController;


原理

不管是往上一页翻还是往下一页翻,他首先都会先响应背面。也就是说,只要我们在响应背面的情况下,我们直接返回一个临时控制器(需被持有),然后为这个临时控制器添加正面的方向截图,并加一个alpha = 0.5的黑色视图层,即可达到跟系统一样的翻页背景效果。(这里我们标记为:往上一页翻时背景控制器为beforeBackVC,往下一页翻时背景控制器为afterBackVC,已经自定义了一个MCDVBackVC。)

开始

由于开启了doubleSided模式,所以上面的两个代理方法都会触发两次,然后第一次肯定是背面,第二次才是正面;所以我们在第一次调用的时候,直接返回对应的临时控制器变量。

这里,有朋友就会想到可以这么做:在返回对应的临时控制器的时候,先正面以反向方式截屏然后添加到该临时控制器。

没错,这个确实是可以,但是有瑕疵。

What???什么瑕疵?

由于控制器在初始化的时候是没有立马进行界面布局约束(需要丢丢时间),也就导致截出来的图片没有考虑到安全区域。

想想看,这样子贴到背面的话,就不能很好的和正面进行反向自然的映射了。

怎么办???

延迟对背面添加截屏的操作!!这样子界面约束完全起作用后,对其截屏才有意义。

由于viewControllerBeforeViewControllerviewControllerAfterViewController这两个方法无法做到延时等待控制器完成布局再进行return操作,所以我把延迟添加截屏到临时控制器的操作放到了下面这个代理方法:

- (void)pageViewController:(UIPageViewController *)pageViewController willTransitionToViewControllers:(NSArray<UIViewController *> *)pendingViewControllers;

该方法是UIPageViewController开始滚动或翻页的时候触发,我们可以在这里处理这个延迟添加视图操作。

这里延迟处理代码段举例:

- (void)pageViewController:(UIPageViewController *)pageViewController willTransitionToViewControllers:(NSArray *)pendingViewControllers {
if (self.pageVC.transitionStyle != UIPageViewControllerTransitionStylePageCurl) return;

/*
UIPageViewControllerTransitionStylePageCurl Only.
*/
[self pageViewController:pageViewController didSetBackViewControllerWithPendingViewController:pendingViewControllers.lastObject];
}

- (void)pageViewController:(UIPageViewController *)pageViewController didSetBackViewControllerWithPendingViewController:(UIViewController *)pendingViewController {
MOJiPageBaseViewController *currentPageBaseVC = pageViewController.viewControllers.lastObject;
MOJiPageBaseViewController *pendingVC = (MOJiPageBaseViewController *)pendingViewController;

dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.05 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
if (currentPageBaseVC.pageIndex == pendingVC.pageIndex + 1) {
//before
[self.beforeBackVC addScreenshotWithVC:pendingVC];
} else {
//afters
[self.afterBackVC addScreenshotWithVC:currentPageBaseVC];
}
});
}

特别说明

1.这里延迟0.05秒触发添加截图的操作,我们人的肉眼基本上看不到有啥延迟,完美达到可以与系统相媲美的翻页效果。
2.如需了解具体的实现,请查看MOJiContentDetailsVC框架相关实现即可。
3.该优化方案几乎满足各种使用UIPageViewController的应用场景。
4.已经在iPhone SE等旧机型真机上进行测试,没问题。
5.由于辞書也支持滚动浏览,所以切勿忘记兼容Scroll类型的交互,否则容易闪退。

总结

该优化拖了大半年多,一直认为的麻烦、复杂,但是最后还是搞定了!
原来打算深色模式下,翻页背景直接搞个黑色背景就好了,因为涉及到延迟处理的问题,嫌麻烦就没搞。后面感觉体验不是很好,最后还是使出洪荒之力对其进行优化。

不断优化用户体验,不断提供产品质量,向精品对齐。