2019-02-22 15:20:59 qq934235475 阅读数 1460
  • 完全征服React Native

    React Native是Facebook于2015年推出的跨平台开发工具,可用于开发Android和iOS App,并且同时具有混合开发的优点(热更新,跨平台)以及本地App的性能。 本课程采用新的ES6开发,主要内容包括ReactNative的基础知识,ReactNative的布局,组件,API,封装本地API和组件,发布ReactNative App,本地与ReactNative深度结合

    58353 人正在学习 去看看 李宁

近来想研究新的动画加载组件,找到了一个react-native-spinkit ,感觉使用起来很不错,记录一下使用的过程。

效果展示: 

 

其他动画效果:

那么,让我们提起裤子开干吧! 


环境版本:

  "react": "^16.2.0",
  "react-native": "^0.53.0",
  "react-native-spinkit": "^1.1.1",

总体步骤:

  1. 导入组件。
  2. iOS 与 Android 原生进行配置。
  3. 开始使用。

一,导入组件

npm install react-native-spinkit --save

注:0.60 以上版本自动 linking (iOS 如果提示找不到,请 cd iOS && pod install)


二,原生配置

Android:https://github.com/maxs15/react-native-spinkit/wiki/Manual-linking

iOS:https://github.com/maxs15/react-native-spinkit/wiki/Manual-linking

参考如上教程即可,有不懂可以提问。


三,使用

我这里考虑到复用性,封装成了一个组件,通过前一页面传入大小,颜色与动画类型,来进行展示,代码如下:

import Spinkiter from 'react-native-spinkit';
import {Modal,View} from 'react-native';
import React, {Component} from 'react';
/**
 *
 * List of available spinkerType
 * CircleFlip
 * Bounce
 * Wave
 * WanderingCubes
 * Pulse
 * ChasingDots
 * ThreeBounce
 * Circle
 * 9CubeGrid
 * WordPress (IOS only)
 * FadingCircle
 * FadingCircleAlt
 * Arc (IOS only)
 * ArcAlt (IOS only)

 */
export default class Spinner extends Component {
    constructor(props) {
        super(props);
    }
    render() {
        return (
            <Modal
               visible={this.props.showSpinner}
               transparent={true}>
                <View
                    style={{
                        flex: 1,
                        justifyContent: 'center',
                        alignItems: 'center',
                        backgroundColor: 'rgba(0, 0, 0, 0.6)'
                    }}>
                    <Spinkiter isVisible={this.props.showSpinner} size={this.props.spinkerSize} type={this.props.spinkerType} color={this.props.spinkerColor}/>
                </View>
            </Modal>
        );
    }
}

项目示例:https://github.com/supervons/commonProject

欢迎关注,star!

2016-04-06 20:43:11 qq_27275015 阅读数 8962
  • 完全征服React Native

    React Native是Facebook于2015年推出的跨平台开发工具,可用于开发Android和iOS App,并且同时具有混合开发的优点(热更新,跨平台)以及本地App的性能。 本课程采用新的ES6开发,主要内容包括ReactNative的基础知识,ReactNative的布局,组件,API,封装本地API和组件,发布ReactNative App,本地与ReactNative深度结合

    58353 人正在学习 去看看 李宁
  1. github上的地址:https://github.com/exponentjs/react-native-tab-navigator
  2. 终端运行:npm install react-native-tab-navigator –save下载
  3. 导入,类似安卓,
    import TabNavigator from 'react-native-tab-navigator';
  4. 在render方法当中使用它:
render() {
        return (
            <View style={styles.container} >
                <TabNavigator>
                    <TabNavigator.Item
                        selected={this.state.selectedTab === '首页'}
                        title="首页"
                        titleStyle={styles.tabText}
                        selectedTitleStyle={styles.selectedTabText}
                        renderIcon={() => <Image style={styles.icon} source={require("/images/ic_home_normal.png")} />}
                        renderSelectedIcon={() => <Image style={styles.icon} source={require("/images/ic_home_checked.png")} />}
                        onPress={() => this.setState({ selectedTab: '首页' })}>
                        <HomeComponent/>
                    </TabNavigator.Item>
                    <TabNavigator.Item
                        selected={this.state.selectedTab === '消息'}
                        title="消息"
                        titleStyle={styles.tabText}
                        selectedTitleStyle={styles.selectedTabText}
                        renderIcon={() => <Image style={styles.icon} source={require("/images/ic_message_normal.png")} />}
                        renderSelectedIcon={() => <Image style={styles.icon} source={require("/images/ic_message_checked.png")} />}
                        onPress={() => this.setState({ selectedTab: '消息' })}>
                        <MessageComponent />
                    </TabNavigator.Item>
                    <TabNavigator.Item
                        selected={this.state.selectedTab === '联系人'}
                        title="联系人"
                        titleStyle={styles.tabText}
                        selectedTitleStyle={styles.selectedTabText}
                        renderIcon={() => <Image style={styles.icon} source={require("/images/ic_contacts_normal.png")} />}
                        renderSelectedIcon={() => <Image style={styles.icon} source={require("/images/ic_contacts_checked.png")} />}
                        onPress={() => this.setState({ selectedTab: '联系人' })}>
                        <ContactComponent />
                    </TabNavigator.Item>
                </TabNavigator>
            </View>
        );
    }

其中可以自定义选中与未选中text和图标的样式,是不是很方便。
HomeComponent, MessageComponent,ContactComponent为子页面,也要先import
5. styles:

let styles = StyleSheet.create({
    container: {
        flex: 1
    },
    tabText: {
        color: "#000000",
        fontSize: 13
    },
    selectedTabText: {
        color: "#999999",
        fontSize: 13
    },
    icon: {
        width: 20,
        height: 20
    }
});

这样就大功告成了

2017-09-01 18:37:35 Tencent_Bugly 阅读数 1834
  • 完全征服React Native

    React Native是Facebook于2015年推出的跨平台开发工具,可用于开发Android和iOS App,并且同时具有混合开发的优点(热更新,跨平台)以及本地App的性能。 本课程采用新的ES6开发,主要内容包括ReactNative的基础知识,ReactNative的布局,组件,API,封装本地API和组件,发布ReactNative App,本地与ReactNative深度结合

    58353 人正在学习 去看看 李宁

本文来自于腾讯Bugly公众号(weixinBugly),未经作者同意,请勿转载,原文地址:http://mp.weixin.qq.com/s/mUzq4NaBHeF3T-NStLzuRw

作者:peterlmeng

导语

最近特别火的狼人杀和最近特别火的React Native会擦出什么样的火花呢?本文和您一同探讨RN性能优化的现实场景。

项目简介:

这里写图片描述

狼人杀游戏是多人实时性游戏,对流畅度等性能都有要求。作为大型游戏,无论从代码规模和迭代速度来看,手Q的安装包和版本迭代速度都无法用native来承载这样的游戏。从而React Native成为了比较好的选择。

手Q React Native 简介

在手Q目前使用的React Native 版本是0.15版本。下面的数据分析都是基于手QRN0.15版本进行的分析数据。

问题分析

Alt text

开发过React Native的同学,大体都对白屏界面有所了解。作为RN原生自带功能,基本上每个使用RN的业务都在优化这一阶段。通过对狼人杀的测试来看,首次从RN启动到渲染,耗时基本有1.7s左右。而这些耗时数据还是在iPhone6s中测试得出,可想低端局的情况可能会更加糟糕。

分析性能

Alt text

工欲善其事必先利其器,要分析其耗时。还得从源头着手,根据常规做法,都会将React Native打包的js拆分成Base Bundle和业务Bundle。从上图,RN 加载流程来看,加载BaseBundle与业务Bundle的耗时是可以有优化空间的。

Alt text
优化的方案和大多数人的思路一样,只需在业务启动前预加载BaseBundle与业务Bundle即可达到优化时间的效果。

目前所遇到的瓶颈

Alt text

Alt text
在优化的开始,我们可能一直把精力放在BaseBundle中,认为BaseBundle是RN的公共库,体积肯定不小。但是从数据来看,我们的狼人杀业务Bundle已经是1.8MB(纯js代码,不包括资源文件)而BaseBundle只有918KB,已经是两倍的体量。现在还只是狼人杀业务的初期,随着业务的快速迭代,业务Bundle只会更快的增加。而过大的业务Bundle所导致的加载时间也会加长。

可能有同学会说,这不是有预加载嘛。我承认,预加载确实解决了绝大部分业务Bundle的加载耗时。但是,并不是每次预加载都可以刚刚好预加载好业务Bundle。虽然业务Bundle加载耗时变长,预加载好的几率就会慢慢变低。

而这不是最关键的行为,最关键的是内存的消耗,我们来看一张图
Alt text
从上图就可以看出,仅仅是BaseBundle,仅仅只是在内存中展开,还没有到运行。这个时候内存消耗已经达到了6MB。而整个狼人杀RN渲染起来,则消耗了20MB以上的内存。而这还没有包括业务使用的内存。在手Q中,内存的消耗是巨大的,而留给狼人杀使用的内存其实已经很少了。从这里可以看出,内存的优化好像更加迫在眉睫。

React Native 按需加载

Alt text

React Native的思路是在业务运行之前,将所有js代码在JavaScriptContext中展开。这个逻辑本身没有什么问题。但是,我们需要改造成按需加载。按需加载的本质就是将不是关键路径的业务RN拆分开,变成插件中的插件。当业务触发到此逻辑的时候,再去将js代码动态展开。达到动态执行的目的。

而我们想要达成按需加载的效果,可能会面临着三个挑战。

  • 1.js在动态运行的时候,代码注入的问题。

  • 2.js模块与模块之间相互引用的问题。

  • 3.打包工具改造的问题。我们来依次看下这三个问题。

动态注入

Alt text
1.从JS层面分析,想要达到JS代码的动态注入。必须要和运行的JS在相同运用域下面。我们通过分析打包后的JS代码得知,必须要在__d(verboseName + 模块名称)作用域下面。

2.从native层面分析,想要达到JS代码的动态注入。则必须要拿到JavaScriptCore中的JSContext。

- (void)enqueueApplicationScript:(NSData *)script
                             url:(NSURL *)url
                      onComplete:(RCTJavaScriptCompleteBlock)onComplete
{
  RCTAssert(onComplete != nil, @"onComplete block passed in should be non-nil");

  RCTProfileBeginFlowEvent();
  [_javaScriptExecutor executeApplicationScript:script sourceURL:url onComplete:^(NSError *scriptLoadError) {
    RCTProfileEndFlowEvent();
    RCTAssertJSThread();

    if (scriptLoadError) {
      onComplete(scriptLoadError);
      return;
    }

    RCTProfileBeginEvent(0, @"FetchApplicationScriptCallbacks", nil);
    [_javaScriptExecutor executeJSCall:@"BatchedBridge"
                                method:@"flushedQueue"
                             arguments:@[]
                              callback:^(id json, NSError *error)
     {
       RCTProfileEndEvent(0, @"js_call,init", @{
         @"json": RCTNullIfNil(json),
         @"error": RCTNullIfNil(error),
       });

       [self handleBuffer:json batchEnded:YES];

       onComplete(error);
     }];
  }];
}

而上述函数则是比较关键的执行函数,需将此函数从RN内核中暴露出来。

模块相互引用

如果要实现按需加载,则主逻辑JS中包含的其他插件JS代码,则不能在主逻辑JS展开的时候运行。我们想要实现这样的效果,则有两个方案可以实施(二选一即可)。

1.跟进JS动态执行的原理,我们可以将主业务JS A中引用插件 B的实现函数使用空方法__d(verboseName + 业务名{空}) 代替。然后等到运行时,再注入相同的方法(__d(verboseName + 业务名{真实方法}) )。等业务触发了插件B逻辑的时候,真正运行的是刚刚注入的B真实方法。

2.懒require

我们平常的业务代码基本是这样引入另外一个模块的

import GameWait from '../gameWait/gameWait';
import NetOperation from '../netOperation/NetOperation';
import GameNight from '../gameOperation/GameNight';
import GameDay from '../gameOperation/GameDay';
import GameState from '../gameState/GameState';
import {GameStateEnum} from '../gameState/GameEnum';

最终打包工具会把他打包成这样的

var _gameWaitGameWait = require('react-
        native/Werewolf.zip.dir/module/gameWait/gameWait.js');
var _gameWaitGameWait2 = _interopRequireDefault(_gameWaitGameWait);
var _netOperationNetOperation = require(
        'react-native/Werewolf.zip.dir/module/netOperation/NetOperation.js');
var _netOperationNetOperation2 = _ 
        interopRequireDefault(_netOperationNetOperation);
var _gameOperationGameNight = require(
        'react-native/Werewolf.zip.dir/module/gameOperation/GameNight.js');
var _gameOperationGameNight2 = _ 
        interopRequireDefault(_gameOperationGameNight);
var _gameOperationGameDay = require(
        'react-native/Werewolf.zip.dir/module/gameOperation/GameDay.js');
var _gameOperationGameDay2 = _ 
        interopRequireDefault(_gameOperationGameDay);

而这些在业务函数体中,会在编译的时候去找寻此文件是否存在。而这样会报错。

正确的做法是在业务逻辑中,再去require其模块。

if (this.state.nowGameStateEnum === GameStateEnum.game_start) {
        var GameWait = require('../gameWait/gameWait');
        this._changeToDay();
        return (
            <GameWait
                onClosePage={this._onCloseWait.bind(this)}
             />
         );
}

在打包工具中展示则是这样的效果。

if (this.state.nowGameStateEnum === _gameStateGameEnum.GameStateEnum.game_start) {
      var GameWait = require('react-native/Werewolf.zip.dir/module/gameWait/gameWait.js');
      this._changeToDay();
      return (
         _React2.default.createElement(GameWait, {
         onClosePage: this._onCloseWait.bind(this)
      }));
}

这样就实现了require的懒加载。实现了先运行主业务,再动态运行插件业务。

打包工具改造

resolve(ReactPackager.createClientFor(options).then(client => {
      log('Created ReactPackager');
      return client.buildBundle(requestOpts)
        .then(outputBundle => {
          log('Closing client');
          client.close();
          return outputBundle;
        })
        .then(outputBundle => deleteBaseBundle(outputBundle))
        .then(outputBundle => processBundle(outputBundle, !args.dev))
        .then(outputBundle => saveBundleAndMap(
          outputBundle,
          args.platform,
          args['bundle-output'],
          args['bundle-encoding'],
          args['sourcemap-output'],
          args['assets-dest']
        ));
    }));

打包工具的改造,重要的是将业务Bundle拆分成不同的插件。这个可以仿照以前BaseBundle与业务Bundle拆分的做法。

按需加载小结

RN按需加载,只是一个思路。当业务逐渐庞大的时候,相信大家都会面临这个问题。不过,安卓则比较幸运一点。RN有一个原生的unbundle命令可以将业务Bundle以每个业务一个js文件。不过unbundle命令不能打出iOS平台的,解释是因为iOS上面对小文件有IO性能的瓶颈。不过,这里我就没有亲自测试过了。不过个人感觉,真正做到按需加载,就得根据业务做不同的打包,不易过大,也不易过小。平衡才是王道。


后续

大家从上文耗时表可以了解到,预加载和按需加载,只是优化了启动耗时的一部分。而RN在执行RunApplication到RNComponent展示出,中间还有800ms的耗时。这部分目前来看,不管是狼人杀大型业务的启动,还是demo业务的启动,都会有这800ms的耗时,应该与业务大小无关。从时间表来看,是js在大量绘制ReactNativeBaseComponent。所以,这部分应该也有优化的空间。后续有进展再和大家分享。


更多精彩内容欢迎关注腾讯 Bugly的微信公众账号:
这里写图片描述

腾讯 Bugly是一款专为移动开发者打造的质量监控工具,帮助开发者快速,便捷的定位线上应用崩溃的情况以及解决方案。智能合并功能帮助开发同学把每天上报的数千条 Crash 根据根因合并分类,每日日报会列出影响用户数最多的崩溃,精准定位功能帮助开发同学定位到出问题的代码行,实时上报可以在发布后快速的了解应用的质量情况,适配最新的 iOS, Android 官方操作系统,鹅厂的工程师都在使用,快来加入我们吧!

2018-09-20 16:52:33 qq_28978893 阅读数 1612
  • 完全征服React Native

    React Native是Facebook于2015年推出的跨平台开发工具,可用于开发Android和iOS App,并且同时具有混合开发的优点(热更新,跨平台)以及本地App的性能。 本课程采用新的ES6开发,主要内容包括ReactNative的基础知识,ReactNative的布局,组件,API,封装本地API和组件,发布ReactNative App,本地与ReactNative深度结合

    58353 人正在学习 去看看 李宁

react-native-loadview

基于React Native实现的界面加载组件,

Installation

npm install react-native-loadview --save

Import into your project

import LoadView from 'react-native-loadview';

Examle useage

用于界面数据处理load状态展示,目前支持两种gif加载方式

<LoadView style={Styles.loadView} visible={this.props.showIndicator} gif='triangles' />
<WebView
    source={{ uri: url }}
    onShouldStartLoadWithRequest={e => this.onShouldStartLoadWithRequest(e)}
    startInLoadingState
    onError={e => this.onError(e)}
    renderLoading={() => <LoadView/>}
    renderError={() => this.renderError()}
    onNavigationStateChange={e => this.onNavigationStateChange(e)}
/>

Properties

属性 描述 类型 默认
iconSize gif大小 PropTypes.number 40
message 加载文本 PropTypes.string
visible 是否显示 PropTypes.bool true
gif gif名称 PropTypes.oneOf(["spinner", "triangles"]) ‘spinner’

GitHub项目地址

2017-10-31 20:57:50 qq_36091581 阅读数 1668
  • 完全征服React Native

    React Native是Facebook于2015年推出的跨平台开发工具,可用于开发Android和iOS App,并且同时具有混合开发的优点(热更新,跨平台)以及本地App的性能。 本课程采用新的ES6开发,主要内容包括ReactNative的基础知识,ReactNative的布局,组件,API,封装本地API和组件,发布ReactNative App,本地与ReactNative深度结合

    58353 人正在学习 去看看 李宁

react-native APP Image加载图片
*react-native APP Image加载图片共有3中方法:
1.加载外部资源的图片(网络图片)

 <Image style={{width:100,height:100}} source={{uri:'https://facebook.github.io/react/img/logo_og.png'}} />

2. 加载本项目图片
2.1 android
在android/app/src/main/res/drawable目录中加入你需要的图片。

<Image style={{width:100,height:100}} source={{uri:'icon'}} />

记住uri对应的图片名称是不包含后缀的。需要重新打包APP,这样图片能够被正确加载并且显示出来。
2.2 ios
——————自己百度,啦啦啦—————————————————
2.3 android和ios均适用
这里写图片描述
在源文件的根目录新建文件夹app,具体看上图。
images.js中写法
这里写图片描述
在pages中的引用:

import LocalImg from '../images'
<Image style={styles.logoimg} 
  source={LocalImg['logo']}
/>

完成了。
3.加载SD卡内的图片
如果要加载手机存储卡上的图片资源,其方式也很简单,假设我现在要加载sdcard根目录下的icon.png。对应的代码如下:

 <Image style={{width:100,height:100}} source={{uri:'file:///sdcard/icon.png'}} />

可以看到使用了file://加上文件的路径/sdcard/icon.png进行加载,当然你还需要加入对应的权限。这样图片就能正确加载了。

没有更多推荐了,返回首页