React-Native 开发总结

1.iOS 运行指定模拟器

react-native run-ios --simulator "iPhone 7 Plus"

第二次运行默认为上一次的模拟器,不过如果重新开启服务器的话,还是会恢复默认

2. 查看所有模拟器

iOS :xcrun simctl list devices
android : adb devices

3.android 运行到安卓模拟器出现问题

one
JS server already running.
Building and installing the app on the device (cd android && ./gradlew installDebug)...

FAILURE: Build failed with an exception.

* What went wrong:
Could not determine java version from '10.0.1'.

* Try:
Run with --stacktrace option to get the stack trace. Run with --info or --debug option to get more log output.
Could not install the app on the device, read the error above for details.
Make sure you have an Android emulator running or a device connected and have
set up your Android development environment:
https://facebook.github.io/react-native/docs/getting-started.html

解决方法:
在当前项目中,进入
android/gradle/wrapper/gradle-wrapper.properties
替换这个为:
`distributionUrl=https://services.gradle.org/distributions/gradle-4.3-rc-2-all.zip

two

解决完上一个,可能还会出现

* What went wrong:
A problem occurred configuring project ':app'.
> Failed to notify project evaluation listener.
   > Could not initialize class com.android.sdklib.repository.AndroidSdkHandler

查看jdk版本:

javac -version

目前官网上说的只支持
Java Development Kit [JDK] 1.8,那就去下一个吧。
http://www.oracle.com/technetwork/java/javase/downloads/jdk8-downloads-2133151.html

下载好之后,进入文件夹:

/Library/Java/JavaVirtualMachines

我这里还有一个 jdk-10.0.1.jdk ,不知道啥时候下的,感觉没啥用,进入刚下的 jdk1.8.0_181.jdk->Contents->Home

如果没有 .bash_profile

执行:touch .bash_profile

如果没有权限,则在前面加 sudo: sudo touch .bash_profile,

vim .bash_profile,粘贴这些信息:

JAVA_HOME=/Library/Java/JavaVirtualMachines/jdk1.8.0_40.jdk/Contents/Home #这个为home的路径,每一个都不一样,注意
PATH=$JAVA_HOME/bin:$PATH:.
CLASSPATH=$JAVA_HOME/lib/tools.jar:$JAVA_HOME/lib/dt.jar:.
export JAVA_HOME
export PATH
export CLASSPATH

使用 source .bash_profile 使配置生效

输入 echo $JAVA_HOME 显示刚才配置的路径

three

接下来还可能出现 adb: command not found的问题,这个时候还是要在 .bash_profile里修改一下文件内容,粘贴如下:

export ANDROID_HOME=/Users/liuyuhang/Library/Android/sdk,这里的 export ANDROID_HOME= #你的安卓sdk路径

如果保存不成功,则用 sudo vim .bash_profile 打开

four

接下来运行成功,but,红屏,按照红屏提示一个一个解决吧。

  • 第一种方法:
  • 在终端输入 adb shell input keyevent 82
  • 点击进入 Dev Settings
  • 点击 Debug server host for device
  • 输入你电脑的IP地址和端口号
  • 重新运行
  • 第二种方法
  • 跟上面相同进入到输入端口号跟 ip
  • 输入localhost:8081
  • 再在终端输入 adb reverse tcp:8081 tcp:8081
  • 重新运行
five

出现

Unable to load script from assets 'index.android.bundle'...

解决办法原文引自网上大神:

* Go to your project directory and check if this folder exists android/app/src/main/assets
i) If it exists then delete two files viz index.android.bundle and index.android.bundle.meta
ii) If the folder assets doesn't exist then create the assets directory there.

* From your root project directory do
cd android && ./gradlew clean

* Finally, navigate back to the root directory and check if there is one single entry file called index.js
i) If there is only one file i.e. index.js then run following command
react-native bundle --platform android --dev false --entry-file index.js --bundle-output android/app/src/main/assets/index.android.bundle --assets-dest android/app/src/main/res

ii) If there are two files i.e index.android.js and index.ios.js then run this
react-native bundle --platform android --dev false --entry-file index.android.js --bundle-output android/app/src/main/assets/index.android.bundle --assets-dest android/app/src/main/res

* Now run react-native run-android

原理是不加载本地的 npm

six

如果还有问题,尝试关闭所有运行的相关程序,重新打开本地服务器操作;另外还有一些灵异事件还在探索中。。

4.iOS 清理 Xcode 缓存

如果发现 iOS 模拟器较多,在 Xcode 中清理一下多余的虚拟机

进入 ~/Library/Developer/Xcode

iOS DeviceSupport 为模拟器的文件夹

5.取消 Xcode 上多余 log

打开 Xcode,Xcode menu -> Product -> Edit Scheme...

Environment Variables -> Add -> Name:

"OS_ACTIVITY_MODE", Value:"disable"

重新运行

基础学习

1.flex

flex 设置为 1 后,是设置占据父容器除了其他子视图外剩下的全部的空间;
默认顶层视图需要用

2.Flexbox布局

  • flexDirection:rowrow 为横向,column 为纵向),在react-native 里默认竖向
  • justifyContent:flex-start
    • flex-start:从第一个视图依次排序布局
    • center:所有子视图会以父视图的中心为基准来贴近
    • flex-end:所有视图贴往右边
    • space-around:稍微靠向两端的对齐排列
    • space-between:靠两遍
    • space-evenly

3.按钮

<Button
  onPress={() => {
    console.log('点我呀');
  }}
  title="点我!"
/>

4.导航栏

1.主推:react-navigation
在项目中安装:yarn add react-navigation

this.props.navigation.navigate('Mine');

this.props.navigation.goBack();

2.利用 react-navigation 完成界面的传值:

A->B,从B中将值传过来:

A中:

this.props.navigation.push('Provices',{
                                getCity:function(city,value){
                                    self.setState({
                                        city:city,
                                        value:value
                                    })
                                }
                            })

B中:

if(this.props.navigation.state.params.getCity){
                let city = data.label
                this.props.navigation.state.params.getCity(city,data.value)
            }
            this.props.navigation.goBack(null);

原理是在push进入B之前,传方法过去,并在B中通过city跟value的值回传给A

5.状态(state):

组件的state是可变的,它负责处理与用户的交互。在通过用户点击事件等操作以后,如果使得当前组件的某个state发生了改变,那么当前组件就会触发render()方法刷新自己。

6.render():

  • 该函数是组件的渲染回调函数,该函数是必须实现的,并且必须返回一个组件或一个包含多个子组件的组件。
  • 该函数可以被调用多次:初始化时的渲染以及state改变以后的渲染都会调用这个函数。

componentDidMount():

  • 在初始化渲染执行之后立刻调用一次,也就是说,在这个函数调用时,当前组件已经渲染完毕了,相当于iOS开发中ViewController里的viewDidLoad方法。
  • 通常在这个方法里执行网络请求操作。

componentWillReceiveProps(object nextProps):

  • 在当前组件接收到新的 props 的时候调用。此函数可以作为 react 在 prop 传入之后, render() 渲染之前更新 state 的机会。新的props可以从参数里取到,老的 props 可以通过 this.props 获取到。
  • 在初始化渲染的时候,该方法不会调用。

shouldComponentUpdate(object nextProps, object nextState)

shouldComponentUpdate: function(nextProps, nextState) {
  return nextProps.id !== this.props.id;
}

当shouldComponentUpdate方法返回false时,讲不会执行render()方法,componentWillUpdate和componentDidUpdate方法也不会被调用

这常用在刷新很多数据的列表上有用。

  • 在接收到新的 props 或者 state,将要渲染之前调用。如果确定新的 props 和 state 不会导致组件更新,则此处应该 返回 false,这样组件就不会更新,减少了性能上不必要的损耗。
  • 该方法在初始化渲染的时候不会调用

componentWillUnmount()

  • 在组件从 DOM 中移除的时候立刻被调用。例如当前页面点击返回键跳转到上一页面的时候就会调用。
  • 通常在这个方法里移除通知。

7.module.exports 方法定义全局样式,比如:

module.exports ={

    //cell分割线样式
    cellBottomLineStyle: {
        height: 0.4,
        opacity:0.5,
        backgroundColor: 'darkgray',
    },
};
    

8.用到的标签需要导入,比如用了 View 跟 Text,需要这样:

import {
    Platform,
    StyleSheet,
    Text,
    View
} from 'react-native';

前面两个为库函数

9.TabNavigator 使用,(现在弃用,因为会提示Method 'jumpToIndex' is deprecated. Please upgrade your code to use jumpTo instead 'Change your code from 'jumpToIndex(1)' to 'jumpTo('...')),改用createBottomTabNavigator

10.PropTypes的引入

引入方式为 import PropTypes from 'prop-types';

路由配置


screen:和导航的功能是一样的,对应界面名称,可以在其他页面通过这个screen传值和跳转。
 
 
navigationOptions:配置TabNavigator的一些属性
{
 
 * title:标题,会同时设置导航条和标签栏的title
 
 * tabBarVisible:是否隐藏标签栏。默认不隐藏(true)
 
 * tabBarIcon:设置标签栏的图标。需要给每个都设置

}

 

11.TextInput 的使用

1.要折行使用:multiline={true}

2.水印:placeholder='请填写备注'

3.从左上开始布局在style里写:

textAlign: 'left',
textAlignVertical: 'top',

4.监听输入内容:

onChangeText={(text) => this.setState({ name: text })}

结束之后的方法:

onEndEditing={(event)=>{
event.nativeEvent.text
}}

5.属性:

  • secureTextEntry:true 为密文
  • autoCapitalize:
    • none:不自动变为大写
    • sentences:将每句话的首字母自动改成大写
    • words:将每个单词的首字母自动改成大写
    • characters:将每个英文字母自动改为大写
  • autoFocus:true 为第一响应者
  • editable :是否可编辑

6.Text 组件可以触发点击事件,而 View 组件没有

7.在安卓上需要给宽度才会显示,高度可以不给

TouchableOpacity 的使用

想要点击时没有闪烁,添加一个属性,将默认点击透明度设置为 1:
activeOpacity = {1}

12.Image 的使用

  1. 属性:resizeMode
  • stretch:图片被拉伸至与容器大小一致,可能会发生变形
  • contain:容器完全容纳图片,图片等比例进行拉伸
  • cover(默认):图片居中显示且不拉伸图片,超出的部分剪裁掉
  1. 获取图片的属性:

在线:Image.getSize(url, (_width, _height) => { });
本地:

3.模糊:blurRadius={20}


const orderImage = Image.resolveAssetSource(require('./images/orderNormal.png'));
console.info(orderImage);

4.在 Android 上潜在的内存泄漏 Bug

在安卓中,加载一张尺寸远大于容器的图片,内存会突然猛涨,在这张图上下滑动,程序就直接因为内存不足而崩溃了如何解决呢?其实办法也很简单,只需要设置 Image 组件的 resizeMethod 属性为 resize 即可

状态栏的显示

<StatusBar
      animated={true} //指定状态栏的变化是否应以动画形式呈现。目前支持这几种样式:backgroundColor, barStyle和hidden
      hidden={false}  //是否隐藏状态栏。
      backgroundColor={this.state.MainColor} //状态栏的背景色
      translucent={true}//指定状态栏是否透明。设置为true时,应用会在状态栏之下绘制(即所谓“沉浸式”——被状态栏遮住一部分)。常和带有半透明背景色的状态栏搭配使用。
      barStyle='light-content'
  />


动画的实现

有些时候由于性能瓶颈,不得不放弃通过触发render的方式来改样式,而是通过setNativeProps 来直接更改原生组件的样式属性 来达到相同的效果

Date 日期的使用

转成时间:

getCurrentTime(){
        var date = new Date();
        // var timestamp2 = ( new Date()).valueOf();
        // alert(timestamp2)
        var year = date.getFullYear().toString();
        var month = (date.getMonth()+1).toString();
        var day = date.getDate().toString();
        var hour =  date.getHours().toString();
        var minute = date.getMinutes().toString();

        return year+'/'+month+'/'+day+'  '+hour+':'+minute
    }

时间转时间戳:

( new Date()).valueOf()

时间戳转时间:

//时间戳转时间
    timestampToTime(timestamp) {
        
        var date = new Date(timestamp);//时间戳为10位需*1000,时间戳为13位的话不需乘1000
        var Y = date.getFullYear() + '-';
        var M = (date.getMonth()+1 < 10 ? '0'+(date.getMonth()+1) : date.getMonth()+1) + '-';
        var D = date.getDate() + ' ';
        var h = date.getHours() + ':';
        var m = date.getMinutes() + ':';
        var s = date.getSeconds();
        return Y+M+D+h+m+s;
    }

注意,时间戳必须不能是字符串

13.FlatList 的使用

<FlatList 
                        keyExtractor ={(item, index) => index.toString()}
                        onLayout={} 
                        data={this.state.loactionData} 
                        renderItem={({item}) => 
                        
}>       
</FlatList>

注意,如果有嵌套的 FlatList,需要把 keyExtractor 替换成 lisKey,还可以

listKey={(item, index) => 'A' + index.toString()}

2.遇到界面可能不会刷新问题:

如果是一个引用类型(Object或者数组都是引用类型),则需要先修改其引用地址(比如先复制到一个新的Object或者数组中),然后再修改其值,否则界面很可能不会刷新。

3.一行实现多列的方法:

FlatList 提供了一个叫 numColumns 的属性,你只需要设置一行的列数,便可轻松实现一行多列的

4.设置 getItemLayout,在高度固定的时候

getItemLayout={(data, index) => (
                    {length: scaleHeight(50), offset: scaleHeight(50) * index, index}
                )}

5.防止快速滑动出现白屏

设置 windowSize={xx} ,指的是屏幕外要渲染的数量

14. ScrollView的使用

监听滑动事件:
onMomentumScrollEnd = {this.contentViewScroll}

注意:如果方法内会用到 this,需要在 constructor(props) 方法里绑定 :this.contentViewScroll = this.contentViewScroll.bind(this);

15. Slider 使用

基本上颜色都可以做调整,除了大小

属性:

minimumValue:滑块的最小值(当滑块滑到最左侧时表示的值),默认为0

maximumValue:滑块的最大值(当滑块滑到最右端时表示的值),默认为1

value:滑块的初始值。这个值应该在最小值和最大值之间,默认值是0

onValueChange:在用户拖动滑块的过程中不断调用此回调,携带一个当前滑块的位置参数

onSlidingComplete:户结束滑动的时候调用此回调

step:滑块的最小步长,这个值应该在0到(maximumValue - minimumValue)之间,默认值为0

thumbImage:给滑块设置一张图片,只支持静态图片

trackImage:给轨道设置一张背景图,只支持静态图片,图片最中央的像素会被平铺直至填满轨道

minimumTrackImage:指定一个滑块左侧轨道背景图,仅支持静态图片。图片最右边的像素会被平铺直至填满轨道

maximumTrackImage:指定一个滑块右侧轨道背景图,仅支持静态图片。图片最左边的像素会被平铺直至填满轨道

minimumTrackTintColor:滑块左侧轨道的颜色,默认为一个蓝色的渐变色

maximumTrackTintColor:滑块右侧轨道的颜色,默认为一个灰色的渐变色

15. setState 属于异步调用

常见问题:

this.setState({key: 'value'},()=>{
    console.log('这里获取最新的数据');
});
console.log('这里获取不到最新的数据');

16. 界面显隐的监听

利用 react-navigation 版本为 2.x 才有的方法,旧版本可以用 onNavigationStateChange + context,现在用 addListener 方法来监听 didFocus 或 didBlur 事件。

componentDidMount() {

        // 添加监听,消失的方法
        // this.viewDidAppear = this.props.navigation.addListener(
        //     'didBlur',
        //     (obj)=>{
                    //这里写方法
        //     }
        // )

        //添加监听,显示的方法
        this.viewDidAppear = this.props.navigation.addListener(
            'didFocus',
            (obj)=>{
                //这里写方法
            }
        )
      }

导航栏配置

tabBarPosition:设置tabbar的位置,iOS默认在底部,安卓默认在顶部。(属性值:'top','bottom')
 
swipeEnabled:是否允许在标签之间进行滑动
 
animationEnabled:是否在更改标签时显示动画
 
lazy:是否根据需要懒惰呈现标签,而不是提前,意思是在app打开的时候将底部标签栏全部加载,默认false,推荐为true
 
trueinitialRouteName: 设置默认的页面组件
 
backBehavior:按 back 键是否跳转到第一个Tab(首页), none 为不跳转
 
tabBarOptions:配置标签栏的一些属性iOS属性
{
 
activeTintColor:label和icon的前景色 活跃状态下
 
activeBackgroundColor:label和icon的背景色 活跃状态下
 
inactiveTintColor:label和icon的前景色 不活跃状态下
 
inactiveBackgroundColor:label和icon的背景色 不活跃状态下
 
showLabel:是否显示label,默认开启 

style:tabbar的样式
 
labelStyle:label的样式安卓属性
 
 
showIcon:是否显示图标,默认关闭
  
pressColor:material涟漪效果的颜色(安卓版本需要大于5.0)
 
pressOpacity:按压标签的透明度变化(安卓版本需要小于5.0)
 
scrollEnabled:是否启用可滚动选项卡 

tabStyle:tab的样式
 
indicatorStyle:标签指示器的样式对象(选项卡底部的行)。安卓底部会多出一条线,可以将height设置为0来暂时解决这个问题
 
 
iconStyle:图标样式
}


10.Platform 作用

如果有两个文件

BigButton.ios.js
BigButton.android.js

只需要导入 import BigButton from './components/BigButton';

然后调用 Platform 的方法即可。

11. https://snack.expo.io/SkG37a0a- 网上模拟器

12.修改iOS的版本

不只是改工程的版本,还要修改工程里Libraries文件夹下所有.xcodeproj的版本

13.字符串获取首位

根据例子:

const [a, b, c, d, e] = 'hello';
a // "h"
b // "e"
c // "l"
d // "l"
e // "o"

字符串长度:

let {length : len} = 'hello';
len // 5

交换变量的值:

let x = 1;
let y = 2;

[x, y] = [y, x];

判断是否创建:

typeof y === 'undefined'

强制显示小数点后两位:

scaleDecimal(x){
        var f = parseFloat(x); 
        if (isNaN(f)) { 
            return false; 
        } 
        var f = Math.round(x*100)/100; 
        var s = f.toString(); 
        var rs = s.indexOf('.'); 
        if (rs < 0) { 
            rs = s.length; 
            s += '.'; 
        } 
        while (s.length <= rs + 2) { 
            s += '0'; 
        } 
        return s; 
    }

将小数跟整数分开:

 // 取小数
 
            var b = a.split(".");//a 必须是字符串,呵呵
            var x=b[0];
            var y=b[1];

判断是否包含中文:

    isChinese(str){
        if(/.*[\u4e00-\u9fa5]+.*/.test(str)){
            return true;
        }else{
            return false;
        }
    }

判断字符串是否包含特定字符:


14.函数

函数只能返回一个值,如果要返回多个值,只能将它们放在数组或对象里返回。有了解构赋值,取出这些值就非常方便。

function example() {
  return [1, 2, 3];
}
let [a, b, c] = example();

// 返回一个对象

function example() {
  return {
    foo: 1,
    bar: 2
  };
}
let { foo, bar } = example();

解构赋值对提取 JSON 对象中的数据,尤其有用。

let jsonData = {
  id: 42,
  status: "OK",
  data: [867, 5309]
};

let { id, status, data: number } = jsonData;

console.log(id, status, number);

箭头函数:

var f = v => v;

// 等同于
var f = function (v) {
  return v;
};
var f = () => 5;
// 等同于
var f = function () { return 5 };

var sum = (num1, num2) => num1 + num2;
// 等同于
var sum = function(num1, num2) {
  return num1 + num2;
};

2.数组的遍历
for in 方法跟 oc 不一样,遍历出来的是数组下标;
for of 方法才是遍历出来数组内对象

3.获取数组内最大值

var arr = [1, 2, 3];
var max = Math.max(...arr);

导航跳转 demo

1.使用系统的导航栏,导入:

yarn add react-navigation

2.在用到的任何界面都要导入:

import { createStackNavigator } from 'react-navigation';

3.在当前项目创建名为 js 文件夹,名字任意取,并创建两个 js 文件,分别为 NavigationPage.js ,NavigationPageNext.js,

4.在 app.js 导入两个文件:

import NavigationPage from './js/NavigationPage';
import NavigationPageNext from './js/NavigationPageNext';

5.在 app.js 配置导航信息:

const RootStack = createStackNavigator(
  {
  // 定义路由页面
  Home: NavigationPage,
  homeNext: NavigationPageNext,

  },
  {
  // 初始化首页
  initialRouteName: 'Home',
  }
  );

6.在 app.jsComponent方法写入:

return <RootStack />;

,这样在运行程序的时候,就会默认显示 NavigationPage 界面信息

7.在 NavigationPage.js 内写

export default class Navigation extends Component {

    render() {
            return (
      <View >
        <Text >Welcome to React Native!</Text>
        <Button
  onPress={() => {
    // this.props.RootStack.navigation.push
    this.props.navigation.push('homeNext');
  }}
  title="点击进入二级页面"
/>
      </View>
    );
    }


}

这个时候可能会报错,导入系统的 Button 组件:

import { Button } from 'react-native';

8.在 NavigationPageNext 界面增加一个返回按钮:

return (
            <View >
              <Text >Welcome to React Native!</Text>
              <Button
        onPress={() => {
          // this.props.RootStack.navigation.push
          this.props.navigation.goBack(null);
        }}
        title="点击进入1级页面"
      />
            </View>
          );

这样就完成了~

动态计算视图高度

有时候因为文本内容不固定,所以在创建组件时不会给确切的高度,比如文本(Text)高度,视图(View)高度,列表(Flatlist)高度。很多时候我们可能不会去计算组件的动态高度,因为即使不给固定的高度,组件也能够自适应的显示该有的东西,但是在涉及到多个不确定高度的组件捆绑在一个组件中时,我们就可能要用到这个属性。

每每个组件都可以设置 onLayout 属性来获取组件的位置信息,这个方法便是在组件加载时获取高度的属性。

例如计算 Flatlist 高度,先在 constructor 中初始化高度,

constructor(props){
        super(props);
        this.state={
            recordCellHeight:0,
        };
    }

定义一个实现计算高度的方法

landCellLayout(event){
      var width = event.nativeEvent.layout.width,
      var height = event.nativeEvent.layout.height,
        this.setState({
              recordCellHeight:height
        })
    }

event 为当前绑定视图的顶级对象,layout属性便是该视图的布局属性,从里面可以获取到对应的视图宽度跟高度。

赋值给组件,

<Flatlist style={{height:this.state.recordCellHeight}} onLayout={this.landCellLayout.bind(this)} />

style 里先给组件高度,然后在 onLayout 里对高度进行重新赋值,需要注意的是要在 this.setState 这个方法里进行数据操作,这样相关视图会得到重新渲染的机会。

另外,也可以不用定义方法,在 onLayout里写方法也是可以的。

<Flatlist style={{height:this.recordCellHeight}} onLayout={(e)=>{
         this.setState({
              recordCellHeight:e.nativeEvent.layout.height
        })
} />

这是计算单个视图的高度方法,向上面所说,如果在一个组件中包含多个组件,并且取高度最大组件的值,可以写一个比较方法来实现。假设组件 A 跟 B,高度分别为 A.height ,B.height。在获取高度的方法中,调用比较方法

Layout(event){
      <!--A.height ,B.height-->
      this.getMaxHeight(A.height,B.height);
      
}

再接着实现 getMaxHeight 方法,主要思路是利用三目运算得出值,最后通过 this.setState 方法刷新布局。

getMaxHeight(x,y){
    var max = x > y?x:y,
    this.setState({
        max:max
    })
}

使用 RNFS

拷贝文件:

RNFS.copyFile(uri,imageUrl)
                    .then(()=>{
                        console.log('copy成功~')
                        DeviceEventEmitter.emit('editPic',{height:self.state.linelength,startDepth:self.state.lineNum,imageUrl:imageUrl,
                            imageWidth:self.state.imageCom.width,imageHeight:self.state.imageCom.height
                            });
                        self.props.navigation.goBack(self.state.keys.A_key);
                    })
                    .catch((error)=>{
                        console.log('copyd~',error)
                    });

注意 imageurl 路径里包含图片名称

使用 react-navagation 跳转指定界面

关键:this.props.navigation.state.key

安装部分三方库出现的问题

以下说的操作路径均是打开Android Studio下
1.安装 react-native-image-picker 的时候,出现 Error: react-native-image-picker:processReleaseResources

第一种解决方案:
androi/app/Gradle Scripts 下面,找到 build.gradle(Module.app),在底部增加这么一句话

subprojects { afterEvaluate {project -> if (project.hasProperty("android")) { android { compileSdkVersion 26 // <-- match this to your project's compileSdkVersion buildToolsVersion '26.0.3' // <-- match this to your project's buildToolsVersion } } } }

第二种方案:直接在那个库里修改

compileSdkVersion 26 // <-- match this to your project's compileSdkVersion
buildToolsVersion '26.0.3' 

2.安装二维码扫描三方库 ac-qrcode 运行出现的问题

第一个问题:
> Could not find method google() for arguments [] on repository container.

解决方法:在 androi/app/Gradle Scripts 下面,找到 build.gradle(Project:项目名) ,将 classpath 里的版本改成 3.0.1

接着会碰到第二个问题:

Error:Minimum supported Gradle version is 4.1. Current version is 2.14.1. If using the gradle wrap

查看一下gradle-wrapper.properties下面的distributionUrl改成它说的最小的 4.1

3.安装 realm 后存储数据

问题1:constructro must be of type 'function',got(undefined)

版本为 realm:2.18.0,
RN :0.56.0

解决方法:回退版本到 2.16.0(注意,不是 ^2.16.0),

终端运行:watchman watch-del-all
rm -rf
TMPDIR/react-native-packager-cache-* rm -rfTMPDIR/metro-bundler-cache-*
rm -rf node_modules/
yarn cache clean
yarn install
yarn start -- --reset-cache

爆红问题归纳

1.

Invariant Violation: Element type is invalid: expected a string( for built-in components) or a class/function (for composite components) but got: object. You likely forgot to export your component from the file it's defined in

如果在导入组件时,是这样导入的话:
import a from './a'

1.需要按照类似这样写:

import { AppRegistry } from 'react-native';
import Header from './src/components/header';

//Create a Component
const App = () => (
  <Header />
);

//Export App - This line solved my issue
export default App;

//Render it to the device
AppRegistry.registerComponent('albums', () => App);
//albums is project name that we use while creating RN App

2.最简单方法是在导入时这样: import {a} from './a' 加个括号即可

2.

attempt to invoke virtual method 'android.graphics.drawable.Drawable android.graphics.drawable.drawable$constantstate.newdrawable(android.content.res.resources)' on a null object reference'

原因:在 Flatlist 组件内包含 TextInput ,并且只在安卓上出现
解决方法:进入 android/app/src/main/res/values/styles.xml 文件内,在这里面把 + 号的内容添加上即可

<resources>
    <!-- Base application theme. -->
    <style name="AppTheme" parent="Theme.AppCompat.Light.NoActionBar">
        <item name="android:windowExitAnimation">@android:anim/fade_out</item>
        <item name="android:windowBackground">@drawable/splash_screen</item>
+       <item name="android:editTextBackground">@android:color/transparent</item>
    </style>
</resources>

3.网络请求成功后没有回调

在 fecth 内走成功的方法中不能用 alert,不然方法会被打断

4.

node_modules/react-native/libraries/animated/src/nodes/animatednode.js:enoent:no such file or directory,uv_cwd(null)

原因:缓存问题,且是在iOS上出现
解决方案:关闭本地服务器,运行:react-native start --reset-cache

5.

Module `***` does not exist in the Haste module map

解决方案npm start -- --reset-cache

6.

Build input file cannot be found: '/Users/me/Desktop/路径/路径/项目/node_modules/react-native/third-party/double-conversion-1.1.5/src/strtod.cc'

原因:只在 Xcode 上出现

解决方案

  • 第一种方法:终端运行 sed -i '' '/DevelopmentTeam = V9WTTPBFK9/d;/DEVELOPMENT_TEAM/d;/ProvisioningStyle = Automatic/d' ./node_modules/react-native/React/React.xcodeproj/project.pbxproj

  • 第二种方法,依次执行两条命令:

    • cd node_modules/react-native/scripts && ./ios-install-third-party.sh && cd ../../../

    • cd node_modules/react-native/third-party/glog-0.3.5/ && ../../scripts/ios-configure-glog.sh && cd ../../../../

7.安卓网络请求失败或者图片加载不出来

尝试使用模拟器的浏览器打开网站,打不开的话模拟器连一下wifi~即可

8.

Could not invoke ImagePickerManager.showImagePicker on Android

这是网络上别人提供的方法:

updating to support-v4 and appcompat-v7 helps me:

com.android.support:appcompat-v7:27.1.1
com.android.support:support-v4:27.1.1

9.Cocopoads安装三方问题

If cocoapods is used and if error RNSVGImage.m:12:9: 'React/RCTImageLoader.h' file not found occurs:

Add the following entry in Podfile:

pod 'React', :path => '../node_modules/react-native', :subspecs => [
    [...]
    'RCTImage', # !!!!!
]

从网页点击跳转到指定 APP

1.iOS 端的实现

1.打开 Xcode,选择工程,然后点击 Info 一栏,点击 URL Types,

image

2.点击 + 号并新增一个 url,只需要在 URL Schemes 中添加一串内容即可。

比如添加的内容是 :luweisurvey

3.然后我们安装 app,在 safari 上输入 luweisurvey:// 就会弹出跳转的提示了

image

2.安卓端的实现

1.进入 AndroidManifest.xml 文件,具体路径为:android->app->AndroidManifest.xml,

2.找到 activity 标签,添加以下标签内容:

<intent-filter>
            <action android:name="android.intent.action.MAIN" />
            <category android:name="android.intent.category.LAUNCHER" />

</intent-filter>
<intent-filter>
            
            <data android:scheme="luweisurvey" />
            <category android:name="android.intent.category.BROWSABLE" />
            <category android:name="android.intent.category.DEFAULT"/>
            <action android:name="android.intent.action.VIEW" />
</intent-filter>

3.根据实际情况修改一下 <data android:scheme="luweisurvey" /> 里的schme内容

4.在安卓手机上,打开浏览器,scheme 内容是什么就输入什么,这里用的是 luweisurvey,那就是输入 luweisurvey:// ,但是这个时候是没有办法跳转的,因为浏览器默认搜索功能,点击搜索就会出来一大堆搜索结果~~。这个时候我们如果需要自己做测试的话,可以写一个网页点击按钮实现跳转到 luweisurvey:// 来实现。

5.随便用一个工具打开一个文本,输入:

<!DOCTYPE html>  
<html>  
<body>
<h1>测试一下</h1> 
<!--自动加载隐藏页面跳转-->
<iframe src="luweisurvey://" style="display:none"></iframe>
<!--手动点击跳转-->
<a href="luweisurvey://">Click</a>
</body>  

保存,格式为 html,然后放到网上,这个怎么操作大家应该都知道~~。

6.然后在手机上点击网页按钮测试成功~

image

注意的地方

1.如果网页端点击跳转失败,那有可能是因为跳转链接是 luweisurvey 而不是 luweisurvey://
2.跳转功能已经可以满足大部分的业务需求,以后再更新跳转到指定界面的攻略~

键盘监听

键盘监听作用是为了在键盘弹起时遮挡了我们想要看到或者输入的内容,对于常规业务的实现来说,我们只需要监听键盘已经出现,以及键盘已经消失就可以了。

具体监听的使用方法也很简单,只有几行代码:

1.创建监听

componentWillMount() {
        //监听键盘弹出事件
    this.keyboardDidShowListener = Keyboard.addListener('keyboardDidShow',
    this.keyboardDidShowHandler.bind(this));

     //监听键盘隐藏事件
     this.keyboardDidHideListener = Keyboard.addListener('keyboardDidHide',
     this.keyboardDidHideHandler.bind(this))
    }

2.实现监听的方法

        //键盘弹出事件响应
      keyboardDidShowHandler(event) {
        //...

    }

      //键盘隐藏事件响应
      keyboardDidHideHandler(event) {
        //...
    }

其中 event 里面包含的内容如下:

{ easing: 'keyboard',
  duration: 250,
  endCoordinates:{ 
    height: 304,键盘高度
    screenX: 0, x轴坐标
    width: 375,键盘宽度
   screenY: 363 y轴坐标
    },
  startCoordinates: { 
      height: 304, 
      screenX: 0, 
      width: 375, 
      screenY: 667 
      }
   }

startCoordinates 是键盘即将弹出时的位置信息,endCoordinates 是键盘已经弹出的位置信息

其实像 textinput 输入框这样的控件,iOS 端使用 IQKeyboardManager,安卓端配置一下文件,是可以实现避免遮盖输入框问题的,不过有些时候,我们不只是需要避免这个,而是还要把输入框下的按钮也能显示出来,这样的话,我们就只能自己动手来实现了。

具体思路是这样的:
1.控件都是写在 scrolleview 上
2.键盘弹起时,获取到键盘当前位置,以及控件的位置,并判断是否出现遮挡
3.遮挡的话,把 scrolleview 的 marginTop 改变一下
4.结束输入时,也就是键盘隐藏后,恢复 scrolleview 的 marginTop的值

获取控件的位置

说到这里应该都知道该怎么做了,现在来教一下怎么获取控件的位置。

倒入必要的系统组件

import { Keyboard,findNodeHandle } from 'NativeModules';
import { UIManager } from 'react-native';

在对应组件中使用:

<Text  ref={(c) => { this.progressBar = c }} onLayout={() => {
    const handle = findNodeHandle(this.progressBar);
                setTimeout(()=>{UIManager.measure(handle, (x, y, width, height, pageX, pageY) => {
               
    console.warn(x, y, width, height, pageX, pageY)
                    // 0, 0, 315, 63, 32, 396.5
})},1000)
            }} />


开发结束

1.studio 安装 apk 到手机

installation failed with message failed to finalize session:install_failed_i

在 build.gradle 里写:

splits {
        abi {
//            reset()
//            enable enableSeparateBuildPerCPUArchitecture
//            universalApk false  // If true, also generate a universal APK
//            include "armeabi-v7a", "x86"

            enable true
            reset()
            include 'x86', 'armeabi-v7a'
            universalApk true

        }
    }

2.移动了安卓文件

把 android 文件夹下的 .gradle,.idea 跟 build 文件夹删掉重新编译

3.安卓图标

只需要放在 :

android/app/src/main/res/mipmap-xhdpi/ic_app_icon.png同时图片一定要保证是 png,如果不是,不能直接改名,而是先导出为 png,没有后缀的时候再添加一个 png 的后缀

4.安卓打包路径

默认路径 release 包:../android/app/build/outputs/apk/release/app-release.apk

5.打包 iOS 方法:

  • 因为react-native 时使用 react-native bundle来进行打包,打包命令为:"bundle-ios":"node node_modules/react-native/local-cli/cli.js bundle --entry-file index.js --platform ios --dev false --bundle-output ./ios/bundle/index.ios.jsbundle --assets-dest ./ios/bundle"因此我们现在 npm脚本内写好打包的命令,也就是快捷键
  • 首先在项目内的 package内,找到 "script",将命令添加保存
  • 在终端运行npm命令 :npm run bundle-ios
  • 这个时候可能会出现 :
* Exploration@0.0.1 bundle-ios: `node node_modules/react-native/local-cli/cli.js bundle --entry-file index.js --platform ios --dev false --bundle-output ./ios/bundle/index.ios.jsbundle --assets-dest ./ios/bundle` 

这个时候不用慌,打开对应路径上的 index.js ,然后修改这个语句:
export default class { ... } -> default class Chicken { .. } 或者改成 export default class Chicken{ .. }

  • 接着重新 npm run bundle-ios
  • 在appdelegate里配置一下bundle:
  //开发包
//  jsCodeLocation = [[RCTBundleURLProvider sharedSettings] jsBundleURLForBundleRoot:@"index" fallbackResource:nil];
  
  //离线包
  jsCodeLocation = [[NSBundle mainBundle] URLForResource:@"bundle/index.ios" withExtension:@"jsbundle"];

6.安卓打包

1.react-native bundle --entry-file index.js --platform android --dev false --bundle-output ./android/app/src/main/assets/index.bundle --assets-dest ./android/app/src/main/res/

2.配置必要证书(jsk)

3.cd android && ./gradlew assembleRelease

问题:

  1. 如果出现:error: Duplicate file. Original is here. The version qualifier may be implied

则使用这句命令

rm -rf android/app/src/main/res/drawable-xxxhdpi android/app/src/main/res/drawable-xxhdpi android/app/src/main/res/drawable-xhdpi android/app/src/main/res/drawable-mdpi android/app/src/main/res/drawable-hdpi

重新执行 ./gradlew assembleRelease

  1. 出现:`Execution failed for task ':app:lintVitalRelease'.

java.lang.NullPointerException (no error message)`

在 build.gradle 里添加

lintOptions { checkReleaseBuilds false }

  1. node_modules/react-native/third-party/glog-0.3.4/test-driver'. Couldn't follow symbolic link.

第一种解决方法:unlink node_modules/react-native/third-party/glog-0.3.4/test-driver

第二种解决方法:

watchman watch-del-all
rm -rf node_modules
rm -rf $TMPDIR/react-*
npm install 
react-native link

安卓:
清除缓存:cd android && ./gradlew clean


插件

React Native Snippet RN的css提示

待解决问题

1.使用DeviceEventEmitter监听,会出现走两次接收的方法
2.怎么判断按钮点击取消?

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 158,117评论 4 360
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 66,963评论 1 290
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 107,897评论 0 240
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 43,805评论 0 203
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,208评论 3 286
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,535评论 1 216
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,797评论 2 311
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,493评论 0 197
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,215评论 1 241
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,477评论 2 244
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 31,988评论 1 258
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,325评论 2 252
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 32,971评论 3 235
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,055评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,807评论 0 194
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,544评论 2 271
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,455评论 2 266