【React Native】进阶指南之一(特定平台、图片加载、动画使用)

1、特定平台代码

  React Native提供了两种方法来区分平台:react

  • 使用Platform模块;
  • 使用特定平台扩展名;

  一、Platform模块

  React Native提供了一个检测当前运行平台的模块;Platform适用于对一小部分代码须要按照平台定制的状况;android

import { Platform, StyleSheet } from "react-native";

const styles = StyleSheet.create({
  height: Platform.OS === "ios" ? 200 : 100
});

  Platform.OS 在iOS上会返回iOS,而在安卓设备或模拟器上则返回android;还要一个实用的方法是Platform.select()ios

import { Platform, StyleSheet } from "react-native";

const styles = StyleSheet.create({
  container: {
    flex: 1,
    ...Platform.select({
      ios: {
        backgroundColor: "red"
      },
      android: {
        backgroundColor: "blue"
      }
    })
  }
});

  1.1 检测Android版本

  在Android上,Version属性是一个数字,标识Andorid的api level;git

import { Platform } from "react-native";

if (Platform.Version === 25) {
  console.log("Running on Nougat!");
}

  1.2 检测iOS版本

  在iOS上,Version属性是-[UIDevice systemVersion]的返回值,具体形式为一个表示当前系统版本的字符串。如:“10.3”github

import { Platform } from "react-native";

const majorVersionIOS = parseInt(Platform.Version, 10);
if (majorVersionIOS <= 9) {
  console.log("Work around a change in behavior");
}

  二、特定平台扩展名spring

  当不一样平台的代码逻辑较为复杂时,最好是放到不一样的文件里,这时候咱们可使用特定平台扩展名。React Native 会检测某个文件是否具备.ios.或是.android.的扩展名,而后根据当前运行的平台自动加载正确对应的文件。react-native

***.ios.js
***.android.js

2、React Native中使用图片

  一、静态图片资源

  React Native提供了一个统一的方式来管理iOS和Android应用中的图片。要往App中添加一个静态图片,只须要把图片放到代码文件夹某处,就能够直接引用。api

<Image source={require('./my-icon.png')} />

  若是你有my-icon.ios.pngmy-icon.android.png,Packager 就会根据平台而选择不一样的文件。缓存

  并且还可使用@2x,@3x这样的文件名后缀,来为不一样的屏幕精度提供图片。安全

.
├── button.js
└── img
    ├── check.png
    ├── check@2x.png
    └── check@3x.png

  Packager会打包全部的图片而且依据屏幕精度提供对应的资源。譬如:iPhone 7 会使用check@2x.png,而 iPhone 7 plus 或是 Nexus 5 上则会使用check@3x.png。若是没有图片刚好知足屏幕分辨率,则会自动选中最接近的一个图片。

  这样会带来以下的一些好处:

  (1)iOS和Android一致的文件系统;

  (2)图片和JS代码处在相同的文件夹,这样组件就能够包含本身所用的图片而不用单独去设置;

  (3)不须要全局命名。不用担忧图片名字冲突问题。

  (4)只有实际被用到(即require)的图片才会被打包到app。

  注意:为了使新的图片资源机制正常工做,require中的图片名字必须是一个静态字符串(不能使用变量,由于require是在编译时期执行,而非运行时期执行)。经过require方式引用的图片包含图片尺寸信息,不须要从新设置width和height.

  二、使用混合App的图片资源

  若是你在编写一个混合 App(一部分 UI 使用 React Native,而另外一部分使用平台原生代码),也可使用已经打包到 App 中的图片资源(以拖拽的方式放置在 Xcode 的 asset 类目中,或是放置在 Android 的 drawable 目录里)。注意此时只使用文件名,不带路径也不带后缀:

<Image source={{uri: 'app_icon'}} style={{width: 40, height: 40}} />

  对于放置在 Android 的 assets 目录中的图片,还可使用asset:/ 前缀来引用:

<Image source={{uri: 'asset:/app_icon.png'}} style={{width: 40, height: 40}} />

  注意:这些作法并无任何安全检查。你须要本身确保图片在应用中确实存在,并且还须要指定尺寸。

  三、Uri数据图片  

  有时候你可能拿到的是图片的 base64 数据,此时可使用'data:'格式来显示图片。请注意,你须要手动指定图片的尺寸

// 请记得指定宽高!
<Image
  style={{
    width: 51,
    height: 51,
    resizeMode: 'contain',
  }}
  source={{
    uri:
      'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAADMAAAAzCAYAAAA6oTAqAAAAEXRFWHRTb2Z0d2FyZQBwbmdjcnVzaEB1SfMAAABQSURBVGje7dSxCQBACARB+2/ab8BEeQNhFi6WSYzYLYudDQYGBgYGBgYGBgYGBgYGBgZmcvDqYGBgmhivGQYGBgYGBgYGBgYGBgYGBgbmQw+P/eMrC5UTVAAAAABJRU5ErkJggg==',
  }}
/>

  四、缓存控制(仅iOS)

  缓存资源属性提供了控制网络层与缓存交互的方式。

  • default:使用原平生台默认策略;
  • reload:URL的数据将从原始地址加载。不使用现有的缓存数据。
  • force-cache:现有的缓存数据将用于知足请求,忽略其期限或到期日。若是缓存中没有对应请求的数据,则从原始地址加载。
  • only-if-cached:现有的缓存数据将用于知足请求,忽略其期限或到期日。若是缓存中没有对应请求的数据,则不尝试从原始地址加载,而且认为请求是失败的。
<Image
  source={{
    uri: 'https://facebook.github.io/react/logo-og.png',
    cache: 'only-if-cached',
  }}
  style={{width: 400, height: 400}}
/>

 3、动画效果的使用

  React Native 提供了两个互补的动画系统:用于建立精细的交互控制的动画Animated和用于全局的布局动画LayoutAnimation

  一、Animated

  Animated使得开发者能够很是容易地实现各类各样的动画和交互方式,而且具有极高的性能。Animated旨在以声明的形式来定义动画的输入与输出,在其中创建一个可配置的变化函数,而后使用简单的start/stop方法来控制动画按顺序执行。 Animated仅封装了四个能够动画化的组件:ViewTextImageScrollView,不过你也可使用Animated.createAnimatedComponent()来封装你本身的组件。下面是一个在加载时带有淡入动画效果的视图:  

import React from 'react';
import { Animated, Text, View } from 'react-native';

class FadeInView extends React.Component {
  state = {
    fadeAnim: new Animated.Value(0),  // 透明度初始值设为0
  }

  componentDidMount() {
    Animated.timing(                  // 随时间变化而执行动画
      this.state.fadeAnim,            // 动画中的变量值
      {
        toValue: 1,                   // 透明度最终变为1,即彻底不透明
        duration: 10000,              // 让动画持续一段时间
      }
    ).start();                        // 开始执行动画
  }

  render() {
    let { fadeAnim } = this.state;

    return (
      <Animated.View                 // 使用专门的可动画化的View组件
        style={{
          ...this.props.style,
          opacity: fadeAnim,         // 将透明度指定为动画变量值
        }}
      >
        {this.props.children}
      </Animated.View>
    );
  }
}

// 而后你就能够在组件中像使用`View`那样去使用`FadeInView`了
export default class App extends React.Component {
  render() {
    return (
      <View style={{flex: 1, alignItems: 'center', justifyContent: 'center'}}>
        <FadeInView style={{width: 250, height: 50, backgroundColor: 'powderblue'}}>
          <Text style={{fontSize: 28, textAlign: 'center', margin: 10}}>Fading in</Text>
        </FadeInView>
      </View>
    )
  }
}

  二、LayoutAnimation API

  LayoutAnimation容许你在全局范围内建立更新动画,这些动画会在下一次渲染或布局周期运行。它经常使用来更新 flexbox 布局,由于它能够无需测量或者计算特定属性就能直接产生动画。尤为是当布局变化可能影响到父节点(譬如“查看更多”展开动画既增长父节点的尺寸又会将位于本行之下的全部行向下推进)时,若是不使用LayoutAnimation,可能就须要显式声明组件的坐标,才能使得全部受影响的组件可以同步运行动画。  

   尽管LayoutAnimation很是强大且有用,但它对动画自己的控制没有Animated或者其它动画库那样方便,因此若是你使用LayoutAnimation没法实现一个效果,那可能仍是要考虑其余的方案。

  要在Android上使用 LayoutAnimation,那么目前还须要在UIManager中启用:

// 在执行任何动画代码以前,好比在入口文件App.js中执行
UIManager.setLayoutAnimationEnabledExperimental &&
  UIManager.setLayoutAnimationEnabledExperimental(true);
import React from 'react';
import {
  NativeModules,
  LayoutAnimation,
  Text,
  TouchableOpacity,
  StyleSheet,
  View,
} from 'react-native';

const { UIManager } = NativeModules;

UIManager.setLayoutAnimationEnabledExperimental &&
  UIManager.setLayoutAnimationEnabledExperimental(true);

export default class App extends React.Component {
  state = {
    w: 100,
    h: 100,
  };

  _onPress = () => {
    // Animate the update
    LayoutAnimation.spring();
    this.setState({w: this.state.w + 15, h: this.state.h + 15})
  }

  render() {
    return (
      <View style={styles.container}>
        <View style={[styles.box, {width: this.state.w, height: this.state.h}]} />
        <TouchableOpacity onPress={this._onPress}>
          <View style={styles.button}>
            <Text style={styles.buttonText}>Press me!</Text>
          </View>
        </TouchableOpacity>
      </View>
    );
  }
}

const styles = StyleSheet.create({
  container: {
    flex: 1,
    alignItems: 'center',
    justifyContent: 'center',
  },
  box: {
    width: 200,
    height: 200,
    backgroundColor: 'red',
  },
  button: {
    backgroundColor: 'black',
    paddingHorizontal: 20,
    paddingVertical: 15,
    marginTop: 15,
  },
  buttonText: {
    color: '#fff',
    fontWeight: 'bold',
  },
});
相关文章
相关标签/搜索