国产探花免费观看_亚洲丰满少妇自慰呻吟_97日韩有码在线_资源在线日韩欧美_一区二区精品毛片,辰东完美世界有声小说,欢乐颂第一季,yy玄幻小说排行榜完本

首頁 > 系統 > Android > 正文

react native結合Android原生實現調用相機或圖庫選擇圖片設置頭像

2019-11-09 18:02:09
字體:
來源:轉載
供稿:網友
這種功能網上已經有了許多開源組件,雖然是現成的,不過也是需要學習如何使用的,集成到自己項目的過程中可能也會遇到一些問題,而且開源的功能也不一定能夠完全的符合自己的需求,所以試著自己實現一下,歡迎大家分享自己的觀點和意見。實現思路很簡單,就是原生部分調用相機將拍照的圖片保存到sd卡,js部分負責顯示。將圖片保存的sd卡是為了下次啟動應用的時候頭像依然有效,也可以上傳到服務器。編寫代碼使用webStorm 和 androidStudio。下面開始實現:首先執行命令 react-native init HeadImage 創建一個名為HeadImage的工程,創建好工程后執行 react-native run-android 看看是否能編譯運行

然后找一張圖片 head_default.png(命名隨意)作為默認頭像,放到工程的 HeadImage/android/app/src/main/res/drawable 目錄下,rn默認工程沒有drawable可以自己新建一個,然后webstorm選擇工程根目錄打開,修改index.android.js代碼

export default class HeadImage extends Component {    render() {        return (            <View style={styles.container}>                <TouchableOpacity onPRess={this._clickImage}>                    <Image source={{uri: 'head_default'}} style={{width:50,height:50}}/>                </TouchableOpacity>            </View>        );    }    _clickImage(){        console.log("click image...");    }}

修改了render方法,t添加_clickImage方法,TouchableOpacity和Image組件別忘了import

注意Image的uri要與自己放在HeadImage/android/app/src/main/res/drawable目錄下的默認頭像圖片命名一致,之后編譯運行(必須編譯運行,因為加了資源圖片,只是reload是不顯示圖片的),運行結果將顯示默認頭像,點擊打出log

接下來實現與原生的交互,參考 http://reactnative.cn/docs/0.31/native-modules-android.html#content

androidstudio打開工程的android目錄

新建兩個類,HeadImageModule.java和HeadImagePackage.java,分別繼承ReactContextBaseJavaModule和ReactPackage,之后在Mainapplication.java里面注冊,各部分代碼如下:

HeadImageModule.java

public%20class%20HeadImageModule%20extends%20ReactContextBaseJavaModule%20{%20%20%20%20public%20HeadImageModule(ReactApplicationContext%20reactContext)%20{%20%20%20%20%20%20%20%20super(reactContext);%20%20%20%20}%20%20%20%20@Override%20%20%20%20public%20String%20getName()%20{%20%20%20%20%20%20%20%20return%20"HeadImageModule";%20//注意這里的返回值%20%20%20%20}%20%20%20%20@ReactMethod%20%20%20%20public%20void%20callCamera()%20{%20//%20調用相機的方法%20%20%20%20%20%20%20%20Log.d("","call%20camera...");%20%20%20%20}}

HeadImagePackage.java

public%20class%20HeadImagePackage%20implements%20ReactPackage%20{%20%20%20%20@Override%20%20%20%20public%20List<NativeModule>%20createNativeModules(ReactApplicationContext%20reactContext)%20{%20%20%20%20%20%20%20%20List<NativeModule>%20modules%20=%20new%20ArrayList<>();%20%20%20%20%20%20%20%20modules.add(new%20HeadImageModule(reactContext));%20%20%20%20%20%20%20%20return%20modules;%20%20%20%20}%20%20%20%20@Override%20%20%20%20public%20List<Class<?%20extends%20JavaScr//%20保存圖片的sd卡路徑private%20static%20final%20String%20HEAD_IMAGE_PATH%20=%20Environment.getExternalStorageDirectory().getAbsolutePath()%20+%20"/HeadImage/";//%20保存圖片的名稱private%20static%20final%20String%20HEAD_IMAGE_NAME%20=%20"head_image.png";// startActivityForResult 的 requestCodeprivate static final int REQUEST_CODE_CAMERA = 0;private static final int REQUEST_CODE_GALLERY = 1;private static final int REQUEST_CODE_CROP = 2;

接下來實現callCamera方法,注意要讓js可以調用必須加@ReactMethod,Promise是與js交互有關的,參考:http://reactnative.cn/docs/0.31/native-modules-android.html#content

@ReactMethodpublic void callCamera(Promise promise) {    recursionDeleteFile(); // 刪除目錄下除了頭像圖片的其他臨時圖片    Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);//啟動相機的intent    if (isPathExists()) { // 判斷常量定義的路徑是否存在,不存在就創建,然后返回true        mFullPath = HEAD_IMAGE_PATH + System.currentTimeMillis() + ".png"; // 臨時圖片        mUri = Uri.fromFile(new File(mFullPath));        intent.putExtra(MediaStore.EXTRA_OUTPUT, mUri);        Activity activity = getCurrentActivity();        if (activity != null) {            mPromise = promise;            activity.startActivityForResult(intent, REQUEST_CODE_CAMERA);        }    }}執行完這個方法就可以啟動相機了,方法中使用臨時圖片是因為拍照->裁剪->完成這個過程用戶可能在某一步取消操作,避免原來的頭像被替換,但是這樣每次調用相機都會創建一個臨時圖片,為了不使sd卡存頭像圖片的文件夾越來越大,所以編寫了recursionDeleteFile()方法每次做一次遞歸刪除,刪除臨時圖片,代碼就不貼了,后面會給出源碼地址。

拍照點擊完成之后,就該去onActivityResult里面處理了,rn提供了一個接口實現監聽onActivityResult,還是看http://reactnative.cn/docs/0.31/native-modules-android.html#content  (或者直接在MainActivity里面重寫onActivityResult方法應該也是可以的,有興趣的可以嘗試一下)

在HeadImageModule.java構造方法里面添加如下代碼

reactContext.addActivityEventListener(new BaseActivityEventListener() {    @Override    public void onActivityResult(Activity activity, int requestCode, int resultCode, Intent data) {        if (requestCode == REQUEST_CODE_CAMERA) { // 調用相機回調            if (resultCode == Activity.RESULT_OK) { // *************1.拍照完成,將進入裁剪界面                activity.startActivityForResult(cropImage(mUri), REQUEST_CODE_CROP);// 啟動裁剪界面            } else if (resultCode == Activity.RESULT_CANCELED) { // 拍照界面點擊取消                mPromise.resolve(null);                // mFullPath就是callCamera里面定義的臨時圖片路徑                // 如果沒有取消拍照,那么就不執行這里,臨時圖片的刪除將在下次調用相機的時候,所以與recursionDeleteFile()不重復                new File(mFullPath).delete();            }        } else if (requestCode == REQUEST_CODE_CROP) { // ************2.裁剪完成            if (resultCode == Activity.RESULT_OK) {                // uri存的是臨時圖片路徑,返回給js代碼,這里有個問題,稍后再說                mPromise.resolve(mUri.toString());                // 將臨時圖片復制一份,保存為最終的頭像圖片                saveHeadImage();            } else if (resultCode == Activity.RESULT_CANCELED) {                mPromise.resolve(null);                new File(mFullPath).delete();            }        }    }});拍照完成將調用系統的裁剪功能
activity.startActivityForResult(cropImage(mUri), REQUEST_CODE_CROP);

cropImage(mUri)方法的實現

private Intent cropImage(Uri uri) {    Intent intent = new Intent("com.android.camera.action.CROP");    intent.setDataAndType(uri, "image/*");    intent.putExtra("crop", "true");    intent.putExtra("aspectX", 1);    intent.putExtra("aspectY", 1);    intent.putExtra("outputX", 800);    intent.putExtra("outputY", 800);    intent.putExtra("return-data", false);    intent.putExtra("scale", true);    intent.putExtra("scaleUpIfNeeded", true);    intent.putExtra(MediaStore.EXTRA_OUTPUT,            Uri.fromFile(new File(mFullPath)));    intent.putExtra("outputFormat", "png");    return intent;}裁剪完成基本就結束了,上面說到有個問題,就是下面代碼裁剪完成的時候返回給js的圖片是臨時圖片,而不是saveHeadImage()保存最終圖片之后返回最終的圖片head_image.png

           if (resultCode == Activity.RESULT_OK) {                // uri存的是臨時圖片路徑,返回給js代碼,這里有個問題,稍后再說                mPromise.resolve(mUri.toString());                // 將臨時圖片復制一份,保存為最終的頭像圖片                saveHeadImage();            } 看js代碼
<Image source={{uri: 'head_default'}} style={{width:50,height:50}}/>

如果uri設置的是最終頭像head_image.png,那么顯示到界面之后,替換sd卡上的最終頭像圖片,命名不變,這時候刷新界面,圖片還是顯示替換之前的頭像,按返回鍵退出,再啟動應用,也是顯示之前的頭像,除非殺死進程再啟動,猜測這個應該跟android的內存機制有關,這就是Java部分就返回臨時圖片的原因。

到這里,頭像圖片已經成功的保存到sd卡上了,接下來就是js顯示的實現了,先理一下,js需要處理的圖片包括三個:默認頭像,sd卡存的臨時頭像,sd卡存的最終頭像。很容易想到,先判斷sd卡的最終頭像是否存在,不存在就用默認頭像,也就是最終頭像優先級高于默認頭像,至于臨時頭像,通過上面的介紹知道只有拍照并且完成裁剪之后才會有臨時頭像傳給js,而這時候臨時的和最終的一樣,其他時候在js里面都是空,所以可以把臨時的優先級看成最高,結果就是先判斷臨時圖片的存在,再判斷最終圖片的存在,都不存在的話使用默認圖片。

邏輯理順了就開始寫代碼,可以新建一個自己的組件,webstorm中在項目的根目錄下新建MyImage.js(命名和路徑隨意),代碼如下:

import React, {Component, PropTypes} from 'react';import {    View,    StyleSheet,    Image,    NativeModules,} from 'react-native';export default class MyImage extends Component {    constructor(props) {        super(props);        this.state = {            uri: null,        };    }    static defaultProps = {        uri: null,    };    static propTypes = {        uri: PropTypes.string,        imageStyle: PropTypes.oneOfType([PropTypes.number, PropTypes.object]),    }    async componentWillReceiveProps() {        let isExists = await NativeModules.HeadImageModule.isImageExists();        if (this.props.uri !== null) {            this.setState({                uri: this.props.uri            });        } else if (isExists) {            this.setState({                uri: await NativeModules.HeadImageModule.getImageUri()            });        } else {            this.setState({                uri: 'head_default'            });        }    }    render() {        return (            <Image source={{uri: this.state.uri}} style={this.props.imageStyle}/>        );    }}需要的文件操作可以使用java然后js調用(仿照camera),自己的組件寫好就可以去用了,修改index.android.js代碼:

首先import自己的組件

import MyImage from './MyImage'
export default class HeadImage extends Component {    constructor(props) {        super(props);        this.state = {            headImageUri: null,        };    }    render() {        return (            <View style={styles.container}>                <TouchableOpacity onPress={this._clickImage.bind(this)}>                    <MyImage uri={this.state.headImageUri} imageStyle={{width: 100,height: 100}}/>                </TouchableOpacity>            </View>        );    }    async _clickImage() {        this.setState({            headImageUri: await NativeModules.HeadImageModule.callCamera() // 相機拍照            // headImageUri: await NativeModules.HeadImageModule.callGallery() // 相冊選擇圖片        });    }    componentDidMount() {        this.setState({            code: this.props.code        });    }}相冊部分和相機相似,到這里就差不多結束了,代碼還有一些地方可以完善,這里就不繼續了,簡單列出一下:

  js部分可以把負責點擊事件處理的TouchableOpacity 寫到自定義組件MyImage里面,當然相應的處理邏輯也在MyImage里面,這樣可以讓自定義組件使用起來更方便

  可以給MyImage增加一個設置頭像存儲路徑的屬性,然后傳給Java部分,java就不用使用常量將頭像的存儲路徑寫死了,可以更加靈活

  可以在頭像的存儲路徑下創建一個.nomedia文件,避免頭像圖片被系統圖庫掃描到

源碼地址:

http://download.csdn.net/download/simple_simple_simple/9749571

https://github.com/developerzjy/react_native_android_headImage


發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
主站蜘蛛池模板: 堆龙德庆县| 龙口市| 龙里县| 灌南县| 新兴县| 宣武区| 丹巴县| 扎鲁特旗| 尼木县| 金坛市| 修文县| 陇南市| 陈巴尔虎旗| 洛隆县| 淳化县| 泉州市| 晋江市| 麦盖提县| 大港区| 威海市| 平谷区| 惠安县| 曲水县| 玉屏| 太和县| 抚顺县| 海阳市| 久治县| 临湘市| 周至县| 囊谦县| 独山县| 朔州市| 应城市| 建宁县| 琼结县| 建水县| 大余县| 石台县| 盘锦市| 运城市|