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閱讀 228,461評論 6 532
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 98,538評論 3 417
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 176,423評論 0 375
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 62,991評論 1 312
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 71,761評論 6 410
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 55,207評論 1 324
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,268評論 3 441
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 42,419評論 0 288
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 48,959評論 1 335
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 40,782評論 3 354
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 42,983評論 1 369
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,528評論 5 359
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 44,222評論 3 347
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 34,653評論 0 26
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 35,901評論 1 286
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 51,678評論 3 392
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 47,978評論 2 374