React-Native 混编应用iOS防白屏启动解决方案

4 篇文章 0 订阅
3 篇文章 0 订阅

 

我通过深入的研究发现,混编应用中第一次从原生打开一个RN页面之所以会出现白屏,有两方面的原因。其一是RN虚拟机本省加载需要耗费时间,但这并不是决定性的影响因素。还有另外一个被大部分人忽视了的原因,就是iOS的加载机制是优先渲染UI,而RN是优先执行底层逻辑。当第一个RN页面被打开的时候,实际上上是执行的如下操作。

实际上iOS系统的UI优先级为第一优先,而RN虚拟机则不是,因此,如果只是对RN的JSBridge等进行缓存处理,对RN模块进行拆包处理,加快了RN页面的加载速度,也不能完全视图过渡动画中出现的白屏,反而是治标不治理本,只能做到理论上的加载优化,但是达不到视觉上的加载优化。但反过来,如果在视图过渡动画中进行一定技巧性处理,则即使没有缓存,没有分包,也可以完美的在混合应用中加载RN页面。

只要稍微分析下iOS页面的视图过渡动画持续时间就知道,原生导航动画,Push、Present,等大概是0.6秒。现在要做的就是自定义一个导航动画,将视图过渡总时长定义为0.7秒,然后延迟0.2秒(0.2秒延迟后再立即执行Push动画,并不会让用户觉得卡顿,具体原因则是视觉效果的范畴了,不信可以拷贝以下代码试一下),再利用剩余的0.5秒时间执行过渡动画。再配合对JSBridge的缓存才能达到事倍功半的效果。同理,对H5页面的加载优化也可以用此法。

在 RN ViewController添加如下代码

//

//  RNRootVC.m

//  RNModule

//

//  Created by 邱弘宇 on 2018/4/16.

//  Copyright © 2018年 YHQiu@github.com All rights reserved.

//

#import "WSRNRootVC.h"

@interface WSRNRootVC ()<UINavigationControllerDelegate>

@end

 

@implementation RNRootVC

- (nullable id <UIViewControllerAnimatedTransitioning>)navigationController:(UINavigationController *)navigationController animationControllerForOperation:(UINavigationControllerOperation)operation fromViewController:(UIViewController *)fromVC toViewController:(UIViewController *)toVC{

 

    if (operation == UINavigationControllerOperationPush) {

        return [WSNavigationAnimator pushAnimator];

    }

    else{

        return nil;

    }

 

}

@end

//

//  NavigationAnimator.h

//  Core

//

//  Created by 邱弘宇 on 2018/1/11.

//  Copyright © 2018年 YHQiu@github.com . All rights reserved.

//

 

#import "WSBaseAnimator.h"

 

@interface WSNavigationAnimator : WSBaseAnimator

 

+ (instancetype)pushAnimator;

 

+ (instancetype)popAnimator;

 

@end

//

//  NavigationAnimator.m

//  Core

//

//  Created by 邱弘宇 on 2018/1/11.

//  Copyright © 2018年 YHQiu@github.com . All rights reserved.

//

 

#import "WSNavigationAnimator.h"

 

#define fromViewOffsetSX 120.f

#define fromViewOffsetSY 0.f

 

#define kSpringWithDamping 0.9f //弹簧震动幅度

#define kInitialSpringVelocity 0.f //弹簧

 

@interface WSNavigationAnimator()

 

@property (nonatomic, assign) int type;

 

@end

 

@implementation WSNavigationAnimator

 

+ (instancetype)pushAnimator{

    WSNavigationAnimator *this = [WSNavigationAnimator new];

    this.type = 0;

    this.transitionDuration = 0.7f;

    return this;

}

 

+ (instancetype)popAnimator{

    WSNavigationAnimator *this = [WSNavigationAnimator new];

    this.type = 1;

    this.transitionDuration = 0.6f;

    return this;

}

 

- (void)animateTransitionEvent {

    if (self.type == 0) {

        [self pushAnimator];

    }

    else{

        [self popAnimator];

    }

}

 

- (void)pushAnimator{

    

    UIView *fromView = self.fromViewController.view;

    UIView *toView = self.toViewController.view;

    UIImageView *fromImgView = [[UIImageView alloc]initWithImage:[self generateImageWithView:[UIApplication sharedApplication].keyWindow scale:[self scale] size:[UIApplication sharedApplication].keyWindow.bounds.size]];

    

    CGRect fromImageViewFrame = CGRectMake(0, 0, fromImgView.frame.size.width, fromImgView.frame.size.height);

    CGRect toViewFrame = CGRectMake(0, 0, toView.frame.size.width, toView.frame.size.height);

    fromImgView.frame = fromImageViewFrame;

    

    self.containerView.backgroundColor = [UIColor whiteColor];

    [self.containerView addSubview:fromImgView];

    [self.containerView addSubview:toView];

    

    CGAffineTransform fromTransform = CGAffineTransformMakeScale(0.8, 0.9);

    fromTransform = CGAffineTransformTranslate(fromTransform, fromViewOffsetSX, fromViewOffsetSY);

    

    CGRect fromeViewInitFrame = fromImageViewFrame;

    fromImageViewFrame.origin.x -= fromViewOffsetSX;

    

    CGRect toViewInitFrame = toViewFrame;

    toViewInitFrame.origin.x += toViewInitFrame.size.width;

    toView.frame = toViewInitFrame;

    

    [UIView animateWithDuration:self.transitionDuration-0.2

                          delay:0.2

         usingSpringWithDamping:kSpringWithDamping initialSpringVelocity:kInitialSpringVelocity options:0 animations:^{

             

             fromImgView.frame = fromImageViewFrame;

             toView.frame = toViewFrame;

             

         } completion:^(BOOL finished) {

             

             [fromImgView removeFromSuperview];

             [self.containerView addSubview:fromView];

             [self completeTransition];

             

         }];

    

}

 

- (void)popAnimator{

    UIView *fromView = self.fromViewController.view;

    UIView *toView = self.toViewController.view;

    UIImageView *fromImgView = [[UIImageView alloc]initWithImage:[self generateImageWithView:[UIApplication sharedApplication].keyWindow scale:[self scale] size:[UIApplication sharedApplication].keyWindow.bounds.size]];

    UIImageView *toImgView = [[UIImageView alloc]initWithImage:[self generateImageWithView:toView scale:[self scale] size:toView.bounds.size]];

    CGRect fromImageViewFrame = CGRectMake(0, 0, fromImgView.frame.size.width, fromImgView.frame.size.height);

    CGRect toImageViewFrame = CGRectMake(0, 0, toImgView.frame.size.width, toImgView.frame.size.height);

    fromImgView.frame = fromImageViewFrame;

    toImgView.frame = toImageViewFrame;

    self.containerView.backgroundColor = [UIColor blackColor];

    [self.containerView addSubview:toImgView];

    [self.containerView addSubview:fromImgView];

    

    CGAffineTransform fromTransform = CGAffineTransformMakeScale(0.8, 0.9);

    fromTransform = CGAffineTransformTranslate(fromTransform, fromViewOffsetSX, fromViewOffsetSY);

    

    CGRect toViewInitFrame = toImageViewFrame;

    toViewInitFrame.origin.x += toViewInitFrame.size.width;

    toImgView.frame = toViewInitFrame;

    

    [UIView animateWithDuration:self.transitionDuration

                          delay:0.0f

         usingSpringWithDamping:kSpringWithDamping initialSpringVelocity:kInitialSpringVelocity options:0 animations:^{

             

             toImgView.layer.affineTransform = fromTransform;

             fromImgView.frame = toImageViewFrame;

             

         } completion:^(BOOL finished) {

             [fromImgView removeFromSuperview];

             [toImgView removeFromSuperview];

             [self.containerView addSubview:toView];

             [self completeTransition];

         }];

    

}

 

- (UIImage *)generateImageWithView:(UIView *)view scale:(CGFloat)scale size:(CGSize)size{

    

    UIImage *image = nil;

    

    @autoreleasepool{

        // 获取当前的context

        UIGraphicsBeginImageContextWithOptions(size, view.opaque, scale);

        CGContextRef context = UIGraphicsGetCurrentContext();

        

        // 在context中绘制图像

        [view.layer renderInContext:context];

        

        // 绘制image

        image = UIGraphicsGetImageFromCurrentImageContext();

        

        // 使当前的context出堆栈

        UIGraphicsEndImageContext();

    }

    

    return image;

    

}

 

- (CGFloat)scale{

    return [UIScreen mainScreen].scale;

}

 

@end

 

/

* 在跳转入口

*

*

/

- (void)jumpMethod{

      UIViewController *vc = [RNRootVC new];

      self.navigationViewController.delegate = vc;

      [self.navigationViewControlller pushToViewController:vc animated:YES];

}

如果要执行Present动画也是同理,自定义对应动画。

GitHub链接: https://github.com/YHQiu/CommixtureTransitionVC

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值