原生与H5交互中实现H5界面的push动画

前言

由于领导的安排,公司做了一个美其名曰混合开发的项目,其原理就是最基本的原生开发+H5开发,通过类似于JSBridge的方式通信,两边定义方法实现,但是h5那边界面是在刷新机制,如果要做到原生的这种push动画效果,不太容易,所以就安排让原生来做,花了一天时间解决了,说一说解决的方案,如果有更好的,欢迎各位补充。

思路:

大概有两种方式,这里抛开一些细节不说,首先要清楚如果要做的话,要知道什么时候是进入,什么时候是退出。因为进入和退出的逻辑动画不同,返回方法可以同前端定义好,在返回的时候拦截,此时这个变量叫true,其他情况就是false,当然在你操作完以后,变量true要主动置为false。

第一种:就是每次拦截url,观察url的改变,很遗憾WK没有代理方法可以监听URl的变化,但是可以通过观察者模式获取变化以后url的值,然后如果是前进的话,就声明一个本类的对象push过去,后退的话就pop出来。

第二种:不生成新的对象,只在本类中用动画效果的方式实现,预备两张图片,一张是当前webView界面的图片,另一张是你要push或者pop到的界面的图片,做图片的动画平移效果。

问题

先说第一种,第一种是最简单的方式,但是问题也是很明显的,抛开性能不说,在push的过程中,界面会有一段时间的白屏,因为wk在加载的时候是需要时间的,并不能做到流畅,很影响用户体验,本人试了一下暂时没有找到更好的解决方法,果断就放弃了。

第二种是个解决方案,但是问题依旧很明显。IOS和安卓不同,安卓可以通过网页缓存直接生成图片,并且安卓是知道什么时候网页渲染完成。如果在前端点击跳转,IOS这边的代理方法是无法知道什么时候网页加载完成了,只有当第一次进这个类的时候,代理方法才会触发,我猜想应该跟Tableview是一个原理,只有在load或者add的时候,才会产生回调,中间过程是无法捕获的。所以这也是为什么连URL都要通过观察者模式去获取了。

具体解决步骤

解决方式:针对无法获取到渲染成功的代理这个问题,换个思路,既然客户端无法知道,可以让前端告诉客户端。另外说一下网上有说可以通过观察者模式观察estimatedProgress这个值是否为1判断,我试了一下,每次进入并不会被观察到。

声明两个属性,一个用来保存上一次获取到的网页界面图片,一个是判断前进还是退出

@property (nonatomic, strong) UIImage *lastSnpImage;
@property (nonatomic, assign) BOOL isGoBack;
复制代码

IOS11以后提供了一个截屏的方法,可以在webView初始化成功以后直接调用,并且将此时生成的图片作为lastSnpImage。因为首页是不需要退出动画的。

截屏2022-05-26 16.24.20.png

截屏2022-05-26 16.28.02.png

每次前进或者后退的时候,都要更新当前的网页界面图片,这样可以保证不会受到线程影响。

截屏2022-05-26 16.31.24.png

截屏2022-05-26 16.33.16.png

imageWithView方法是把当前的view主动截屏,这个方法不会block回调,而takeSnapshotWithConfiguration这个方法是对webview截屏,而此时webview其实已经渲染完成了,无法获取到上一个界面的内容了。

-(UIImage *)imageWithView:(UIView *)view

{

    UIGraphicsBeginImageContextWithOptions(view.bounds.size, view.opaque, 0.0f);

    [view.layer renderInContext:UIGraphicsGetCurrentContext()];

    UIImage *snapshotImage = UIGraphicsGetImageFromCurrentImageContext();

    UIGraphicsEndImageContext();

    return snapshotImage;

}
复制代码

这里说一下为什么要平移两张图片,如果只是last图片,因为webview在平移前已经加载完成了,会导致你的动画效果就像翻书一样,只是当前页的向左或者向右滑动。

需要注意的是,在渲染完成以后,把isGoBack要置NO,如果前端无法判断是前进还是后退的话,这边只有在后退的方法中才会赋值YES。

在需要前进后退的地方做平移动画即可,平移的方式有很多,可以创建了一个view覆盖在上面,这个view的大小是两倍的手机宽度,分别放置两个图片,如果是退出,相当于从屏幕外右移,如果是进入,相当于从0起点移动到屏幕外,具体就不说了。

做的这基本上效果实现了,但是仍然有个小问题,就是每次点击进入或者退出的时候,屏幕都会闪一下,通过打断点可以找到问题所在,是因为webView在生成成功以后,还没来及作动画,下一界面已经渲染完成了,此时对WebView操作不管是隐藏或者大小控制,都会在视觉上影响,因为takeSnapshotWithConfiguration这个方法是异步回调,解决方法是声明一个属性view作为蒙版,在还没有进入takeSnapshotWithConfiguration之前,接收到前进或者后退方法之后,初始化这个蒙版view,然后覆盖在view上,并且把last图片加上去,在完成以后,移除这个蒙版view即可。

截屏2022-05-26 17.00.35.png

截屏2022-05-26 17.01.19.png

猜你喜欢

转载自juejin.im/post/7101967887199371295