ReactNative入門(安卓)——API(上)

Alert - 彈窗html

經過 Alert.alert() 方法調用喚起原生彈窗,點擊會觸發 onPress 回調(參考下方代碼)並清除彈窗。node

import React, {
    AppRegistry,
    Component,
    StyleSheet,
    Alert,
    Text,
    View
} from 'react-native';

class AwesomeProject extends Component {
    componentDidMount(){
        Alert.alert(
            'Alert標題',
            '一些正文內容',
            [
                //{text: '稍後詢問', onPress: () => console.log('Ask me later pressed')},
                //{text: '取消', onPress: () => console.log('Cancel Pressed')},
                {text: 'OK', onPress: () => console.log('OK Pressed')}
            ]
        )
    }
    render() {
        return (
            <View style={styles.container}>
                <Text style={styles.text}>
                    DEMO
                </Text>
            </View>
        );
    }
}
View Code

按鈕數量將決定其排版(下圖),不一樣於ios,安卓沒法定義按鈕樣式:react

(單個按鈕狀況)ios

(兩個按鈕狀況)git

(三個按鈕狀況)github

Animated - 動畫接口web

篇幅較大,故獨立寫了兩篇文章:json

ReactNative入門 —— 動畫篇(上)react-native

ReactNative入門 —— 動畫篇(下)數組

AppRegistry - APP註冊接口

最經常使用的接口,特別是 AppRegistry.registerComponent 方法,用於註冊根組件到當前APP,進而讓原生系統加載時能夠執行對應的bundle文件:

AppRegistry.registerComponent('AppName', () => RootComponent);

除了 registerComponent 以外,還提供了其它一些比較少用的接口:

registerConfig(config<Array>)  //註冊配置
registerRunnable(appKey<String>, func<Function>)  //註冊函數監聽
getAppKeys()  //獲取registerRunnable註冊的監聽鍵
runApplication(appKey<String>, appParams<any>)  //運行App

AppState - 應用狀態

經過此接口能夠獲悉應用在當前處於後臺仍是前臺激活的狀態,經常使用方法和應用場景相似於h5的visibilitychange。

注意該接口要最新版本(2.0+)的 react-native 才能調用。

獲取到的應用狀態常規有:

active:表示應用處於前臺運行狀態;
background:表示應用處於後臺掛起狀態;
inactive:過渡狀態,常規不會發生,能夠先忽略該狀態。

咱們可使用 AppState.addEventListenerAppState.removeEventListener 方法來監聽、移除應用狀態的 change 事件。

另外也能夠直接使用 AppState.currentState 來得到應用當前的狀態:

import React, {
    AppRegistry,
    Component,
    StyleSheet,
    Alert,
    AppState,
    Text,
    View
} from 'react-native';

class AwesomeProject extends Component {
    componentDidMount() {
        AppState.addEventListener('change', this._handleAppStateChange);
        //組件掛載時獲取當前狀態
        Alert.alert('當前狀態', AppState.currentState, [{text: 'OK'}]);
    }

    componentWillUnmount() {
        AppState.removeEventListener('change', this._handleAppStateChange);
    }

    _handleAppStateChange(currentAppState) {
        currentAppState==='active' && Alert.alert('狀態轉變', currentAppState, [{text: 'OK'}])
    }

    render() {
        return (
            <View style={styles.container}>
                <Text style={styles.text}>
                    DEMO
                </Text>
            </View>
        );
    }
}
View Code

注:若是在模擬器中出現「screenPhysicalPixels undefined」的問題,試着執行 react-native upgrade 來更新gradle(見此issue

AsyncStorage - 異步存儲

相似於 localStorage,經常使用於本地存儲一些鍵值對類型的數據,這些存儲的數據對應整個應用自己而已經是全局性質的(相似 localStorage 在同個域下共享)

其對外方法主要有:

getItem(key<String>, [callback<Function(error, result)>])
獲取單個數據,返回一個 Promise 對象

setItem(key<String>, [callback<Function(error)>])
設置單個數據,返回一個 Promise 對象

removeItem(key<String>, [callback<Function(error)>])
移除單個數據,返回一個 Promise 對象

mergeItem(key<String>, value<String>, [callback<Function(error)>])
合併某個已存在的數據項,一般該項爲stringified json格式。該接口返回一個 Promise 對象

clear([callback<Function(error)>])
清除所有 AsyncStorage 數據,返回一個 Promise 對象

getAllKeys(callback<Function(error, keys)>)
獲取全部鍵,返回一個 Promise 對象
flushGetRequests() 清空全部進行中的查詢 multiGet(keys<Array>, [callback<Function(error, keys)>]) 
獲取多項,查詢 keys(字符串數組)指定的多個鍵來查詢對應的值。該接口返回一個 Promise 對象

multiGet(keys<Array>, [callback<Function(error, keyValuePairs)>]) 
獲取多項,參數 keys 是一個字符串數組,回調裏的形參 keyValuePairs 是字符串的二維數組,表示最終得到的鍵值對組。該接口返回一個 Promise 對象

multiSet(keyValuePairs<Array>, [callback<Function(error, keys)>]) 
設置多項,參數 keyValuePairs 是字符串的二維數組。該接口返回一個 Promise 對象

multiRemove(keys<Array>, [callback<Function(error)>]) 
移除 keys(字符串數組)指定的多項。返回一個 Promise 對象

multiMerge(keyValuePairs<Array>, [callback<Function(error)>]) 
合併多項已有的鍵值對,參數 keyValuePairs 是字符串的二維數組。該接口返回一個 Promise 對象。注意該接口還不完善,未能被全部原生支持。

先來看一個簡單的 AsyncStorage 數據設置與獲取:

import React, {
    AppRegistry,
    Component,
    StyleSheet,
    Alert,
    AsyncStorage,
    Text,
    View
} from 'react-native';

class AwesomeProject extends Component {
    constructor(props) {
        super(props);
        this.state = {
            time : '123'
        };
    }
    componentDidMount() {
        AsyncStorage.setItem('timeStamp', Date.now() + '', function(err){
            //錯誤處理
            err && console.log(err)
        }).done(function(){
            Alert.alert(
                '恭喜',
                '數據設置成功',
                [
                    {text: 'OK', onPress: () => {}}
                ]
            )
        })
    }
    _getData() {
        AsyncStorage.getItem('timeStamp', function(err, data){
            if(err) return console.log(err);
            this.setState({
                time : data
            })
        }.bind(this));
    }

    render() {
        return (
            <View style={styles.container}>
                <Text style={styles.text}>
                    {this.state.time || '暫無數據'}
                </Text>

                <View style={styles.btnWrap}>
                    <Text style={styles.btn} onPress={this._getData.bind(this)}>點我獲取</Text>
                </View>
            </View>
        );
    }
}
View Code

再來一個 multiSet 和 multiGet 的示例:

class AwesomeProject extends Component {
    constructor(props) {
        super(props);
        this.state = {
            a : ''
        };
    }
    componentDidMount() {
        var me = this;
        AsyncStorage.multiSet([['a','1'], ['b','2']], function(err){
            if(err) return console.log(err);
            AsyncStorage.multiGet(['a', 'b'], function(err, keyValuePairs) {
                keyValuePairs.forEach(function (keyValuePair) {
                    if (keyValuePair[0] === 'a') {
                        me.setState({
                            a: keyValuePair[1]
                        })
                    }
                });
            })
        })
    }
    _mergeData() {
        var me = this;
        AsyncStorage.multiSet([['a','5'], ['c','2']], function(err){
            if(err) return console.log(err);
            AsyncStorage.getItem('a', function(err, value) {
                me.setState({
                    a: value
                })
            })
        })
    }

    render() {
        return (
            <View style={styles.container}>
                <Text style={styles.text}>
                    {this.state.a || '加載中'}
                </Text>

                <View style={styles.btnWrap}>
                    <Text style={styles.btn} onPress={this._mergeData.bind(this)}>點我合併</Text>
                </View>

                <View style={styles.btnWrap}>
                    <Text style={styles.btn} onPress={AsyncStorage.getItem.bind(this, ['0',{}])}>點我reload</Text>
                </View>
            </View>
        );
    }
}
View Code

注意 multiMerge 接口還不能被全部原生環境支持,調用的時候極可能會直接報錯。事實上能夠直接用 multiSet 替代。

BackAndroid - 返回處理

能夠經過該接口來處理應用返回事件。

經過 BackAndroid.addEventListener 和 BackAndroid.removeEventListener 事件,能夠監聽/移除用戶點擊安卓設備系統返回鍵的事件。

經過 BackAndroid.exitApp() 方法能夠直接退出當前應用:

class AwesomeProject extends Component {
    constructor(props) {
        super(props);
        this.state = {
            a : ''
        };
    }
    componentDidMount() {
        BackAndroid.addEventListener('hardwareBackPress', this._handleBackPressed.bind(this));
    }
    componentWillUnmount() {
        BackAndroid.removeEventListener('change', this._handleBackPressed.bind(this));
    }
    _handleBackPressed() {
        this.setState({
            a : 'backPressed'
        })
    }
    _exitApp() {
        BackAndroid.exitApp()
    }

    render() {
        return (
            <View style={styles.container}>
                <Text style={styles.text}>
                    {this.state.a || '加載中'}
                </Text>

                <View style={styles.btnWrap}>
                    <Text style={styles.btn} onPress={this._exitApp.bind(this)}>退出應用</Text>
                </View>
            </View>
        );
    }
}

效果1——點擊系統返回鍵:

效果2——調用 exitApp 方法:

CameraRoll - 相冊接口

與相冊交互的接口,然而安卓這塊沒IOS的支持好用(沒法保存非本地圖片)。

1. 經過 CameraRoll.saveImageWithTag(uri) 能夠保存某張本地圖片到相冊,其中 uri 必須爲本地地址(例如 'file:///sdcard/img.png')

該接口返回一個 Promise 對象(成功時的回調參數爲圖片存儲後的圖片ID):

    _handleSavePic() {
        var me = this;
        CameraRoll.saveImageWithTag('file:///sdcard/img.png').done(function(uri){
            me.setState({
                a : uri
            })
        }, function(err){
            Alert.alert(
                '保存失敗',
                JSON.stringify(err),
                [
                    {text: 'OK'}
                ]
            )
        })
    }

2. 經過 CameraRoll.getPhotos(params<Object>) 能夠從相冊裏去獲取圖片,其中 params 參數格式爲:

{
  first : 3,  //獲取圖片的個數
  groupTypes : React.propTypes.oneOf([  //分組類型
      'Album',
      'All',
      'Event',
      'Faces',
      'Library',
      'PhotoStream',
      'savePhotos'
  ]),
  assetType : React.propTypes.oneOf([  //資源類型
      'Photos',
      'All',
      'Videos'
  ])
}

該接口返回一個 Promise 對象,成功的回調參數數據格式爲:

{
  edges: [{
      node: {
          timestamp: 1405312098,
          group_name: 'CameraRoll',
          type: 'ALAssetTypePhoto',
          image: {
              isStored: true,
              height: 669,
              uri: 'asset-library: //asset/assert.JPG?id=C9DB366F-350876C78006&ext=JPG',
              width: 1008
          }
    },
    {node: ....}
  }],
  page_info: {
      has_next_page: true,
      start_cursor: 'asset-library: //asset/assert.JPG?id=C9DB366F-350876C78006&ext=JPG',
      end_cursor: 'asset-library...'
  }
}
//參考至「ReactNative入門與實戰」一書162頁

來個簡單示例:

    _handleGetImages() {
        var me = this;
        var params = {
            first : 3,
            groupTypes : 'Album',
            assetType : 'Photos'
        };
        CameraRoll.getPhotos(params).done(function(data){
            var edges = data.edges,
                photos = [];
            edges.forEach(function(edge){
                photos.push(edge.node.image.uri)
            });
            me.setState({
                photos: photos
            })
        }, function(err){
            Alert.alert(
                '打開相冊失敗',
                JSON.stringify(err),
                [
                    {text: 'OK'}
                ]
            )
        })
    }

Clipboard - 剪切板

該模塊接口具備獲取/設置剪切板內容的能力。

經過 Clipboard.getString() 能夠得到設備剪切板內容,經過 Clipboard.setString(content<String>) 能夠設置剪切板內容:

class AwesomeProject extends Component {
    constructor(props) {
        super(props);
    }
    _onPress(){
        Clipboard.setString('你好啊')
    }

    render() {
        return (
            <View style={styles.container}>
                <TouchableOpacity>
                    <View style={[styles.button,{backgroundColor:'#CCC'}]}>
                        <TextInput />
                    </View>
                </TouchableOpacity>

                <TouchableOpacity onPress={this._onPress}>
                    <View style={styles.button}>
                        <Text style={styles.buttonText}>修改剪切板內容爲「你好啊」</Text>
                    </View>
                </TouchableOpacity>
            </View>
        );
    }
}

DatePickerAndroid - 日期選擇器

經過 DatePickerAndroid.open(options<Object>) 方法能夠打開一個標準的Android時間選擇器的對話框,並返回一個Promise對象。

其中 options 參數參考以下:

date (Date對象或毫秒時間戳) - 默認顯示的日期
minDate (Date對象或毫秒時間戳) - 可選的最小日期
maxDate (Date對象或毫秒時間戳) - 可選的最大日期

Promise的回調參數爲: 

action - 對應動做,若爲取消對話框,該值爲 DatePickerAndroid.dismissedAction
year - 選中的年份,若爲取消對話框,該值爲undefined
month (0-11) - 選中的月份,若爲取消對話框,該值爲undefined
day - 選中的天值,若爲取消對話框,該值爲undefined

所以咱們能夠經過判斷 Promise 回調中的 action 是否等價於 DatePickerAndroid.dismissedAction,來得知用戶是否作了取消對話框的行爲:

class AwesomeProject extends Component {
    constructor(props) {
        super(props);
    }
    _onPress(){
        DatePickerAndroid.open({
            date: new Date(),
            minDate: new Date('1900/01/01'),
            maxDate: new Date('2100/12/12')
        }).done(function(params){
            var content = '';
            if(params.action !== DatePickerAndroid.dismissedAction){
                content = '你選中了' + params.year + '年' + (params.month+1) + '月' + params.day + '日'
            } else {
                content = '你退出了時間選擇對話框'
            }

            Alert.alert(
                '時間選擇結果',
                content,
                [
                    {text: 'OK', onPress: () => console.log('OK Pressed')}
                ]
            )
        })
    }

    render() {
        return (
            <View style={styles.container}>
                <TouchableOpacity onPress={this._onPress}>
                    <View style={styles.button}>
                        <Text style={styles.buttonText}>打開日期選擇器</Text>
                    </View>
                </TouchableOpacity>

                <TouchableOpacity>
                    <View style={styles.button}>
                        <Text style={styles.buttonText}>somebtn</Text>
                    </View>
                </TouchableOpacity>
            </View>
        );
    }
}
View Code

Dimensions - 獲取應用窗口尺寸

可經過 Dimensions.get('window') 來獲取當前窗口尺寸,獲得一個含有 width 和 height 屬性的對象。

經常使用於設置圖片寬高(例如設置圖片寬度爲屏幕寬度):

import React, {
    AppRegistry,
    Component,
    StyleSheet,
    Dimensions,
    Text,
    View
} from 'react-native';

class AwesomeProject extends Component {
    constructor(props) {
        super(props);
        this.state = {
            width : '',
            height : ''
        };
    }
    componentDidMount() {
        var win_info = Dimensions.get('window');
        this.setState({
            width: win_info.width,
            height: win_info.height
        })
    }
    render() {
        return (
            <View style={styles.container}>
                <Text style={styles.text}>
                    屏幕寬度:{this.state.width || '加載中'}
                </Text>
                <Text style={styles.text}>
                    屏幕高度:{this.state.height || '加載中'}
                </Text>
            </View>
        );
    }
}

啓動後顯示效果以下:

InteractionManager - 交互管理器

在web頁面,咱們常規會使用 setImmediate/setTimeout/requestAnimationFrame 來定義動畫下一幀的執行時間點,在 RN 的動畫交互中,咱們經過使用 InteractionManager.runAfterInteractions() 來作對應處理是最佳的選擇。

例如咱們但願安卓切換場景的時候,能在場景切換動畫結束了纔開始執行某些操做,能夠這麼寫:

componentDidMount: function(){
    InteractionManager.runAfterInteractions(() => {
        //TODO: some events
    });
}

另外咱們能夠經過 createInteractionHandle() 接口建立一個交互句柄,通知系統當前有個動畫交互開始了。

動畫結束時再經過 clearInteractionHandle(handle) 來通知系統該動畫交互已結束。

示例:

var handle = InteractionManager.createInteractionHandle();
// 開始執行某些動畫交互... (`runAfterInteractions` 任務會被壓入隊列中等候動畫結束)
// 動畫交互執行完畢的時候執行clearInteractionHandle通知系統交互結束:
InteractionManager.clearInteractionHandle(handle);
// 觸發runAfterInteractions

另外 InteractionManager 還有一個靜態方法 setDeadline(deadline<Number>),用於(使用setTimeout來)掛起全部還沒有執行的任務。

donate

相關文章
相關標籤/搜索