模板版本:v0.3.0
本项目基于 [email protected] 开发。
Version | Package Name | Repository | Release |
---|---|---|---|
<= 0.40.3-0.0.14@deprecated | @react-native-oh-tpl/react-native-image-crop-picker | Github(deprecated) | Github Releases(deprecated) |
>= 0.40.4 | @react-native-ohos/react-native-image-crop-picker | Gitee | Gitee Releases |
进入到工程目录并输入以下命令:
npm install @react-native-ohos/react-native-image-crop-picker
yarn add @react-native-ohos/react-native-image-crop-picker
下面的代码展示了这个库的基本使用场景:
[!TIP] 使用时 import 的库名不变。
import ImagePicker from 'react-native-image-crop-picker';
import { openPicker } from 'react-native-image-crop-picker';
import React from 'react';
import { Text, StyleSheet, TextInput, View, Button, ScrollView, Switch } from 'react-native';
const ImageCropPickDemo = () => {
const TAG: string = 'ImageCropPickerTurboModule';
const [maxFiles, setMaxFiles] = React.useState('');
const [imageQuality, setImageQuality] = React.useState('');
const [imagePath, setImagePath] = React.useState('');
const [clearImagePath, setClearImagePath] = React.useState('');
const [cropperTitle, setCropperTitle] = React.useState('');
const [chooseText, setChooseText] = React.useState('');
const [chooseColor, setChooseColor] = React.useState('');
const [cancelText, setCancelText] = React.useState('');
const [cancelColor, setCancelColor] = React.useState('');
const [cropperRotate, setCropperRotate] = React.useState(false);
const [showCropGuidelines, setShowCropGuidelines] = React.useState(true);
const [showCropFrame, setShowCropFrame] = React.useState(true);
const [multiple, setMultiple] = React.useState(false);
const [includeExif, setIncludeExif] = React.useState(false);
const [avoidEmptySpace, setAvoidEmptySpace] = React.useState(false);
const [writeTempFile, setTempFile] = React.useState(true);
const [includeBase64, setBase64] = React.useState(false);
const [freeStyleCropEnabled, setFreeStyleCropEnabled] = React.useState(false);
const [forceJpg, setForceJpg] = React.useState(false);
const [showsSelectedCount, setShowsSelectedCount] = React.useState(true);
const [selectedButton, setSelectedButton] = React.useState('any');
const [useFrontCamera, setUseFrontCamera] = React.useState(false);
const [croppingCamera, setCroppingCamera] = React.useState(false);
const [writeTempFileCamera, setTempFileCamera] = React.useState(true);
const [includeBase64Camera, setBase64Camera] = React.useState(false);
const [includeExifCamera, setIncludeExifCamera] = React.useState(false);
const [avoidEmptySpaceCamera, setAvoidEmptySpaceCamera] = React.useState(false);
const [freeStyleCropEnabledCamera, setFreeStyleCropEnabledCamera] = React.useState(false);
const [forceJpgCamera, setForceJpgCamera] = React.useState(false);
const [mediaTypeCamera, setMediaTypeCamera] = React.useState('any');
const [imageQualityCamera, setImageQualityCamera] = React.useState('');
const [cropperTitleCamera, setCropperTitleCamera] = React.useState('');
const [chooseTextCamera, setChooseTextCamera] = React.useState('');
const [chooseColorCamera, setChooseColorCamera] = React.useState('');
const [cancelTextCamera, setCancelTextCamera] = React.useState('');
const [cancelColorCamera, setCancelColorCamera] = React.useState('');
const [cropperRotateCamera, setCropperRotateCamera] = React.useState(false);
const [showCropGuidelinesCamera, setShowCropGuidelinesCamera] = React.useState(true);
const [showCropFrameCamera, setShowCropFrameCamera] = React.useState(true);
const [writeTempFileCropper, setTempFileCropper] = React.useState(true);
const [forceJpgCropper, setForceJpgCropper] = React.useState(false);
const [includeBase64Cropper, setBase64Cropper] = React.useState(false);
const [includeExifCropper, setIncludeExifCropper] = React.useState(false);
const [avoidEmptySpaceCropper, setAvoidEmptySpaceCropper] = React.useState(false);
const [freeStyleCropEnabledCropper, setFreeStyleCropEnabledCropper] = React.useState(false);
const [imageQualityCropper, setimageQualityCropper] = React.useState('');
const handleButtonPress = (buttonName) => {
setSelectedButton(buttonName);
};
const handleMediaType = (buttonName) => {
setMediaTypeCamera(buttonName);
};
return (
<ScrollView style={styles.container}>
<Text style={styles.title}>相机、图库、裁剪功能:</Text>
<View style={styles.container}>
<View style={styles.TextInputBox}>
<Text style={styles.inputLable}>multiple:</Text>
<Button
title={`${multiple}`}
onPress={() => multiple ? setMultiple(false) : setMultiple(true)}
/>
<Text style={styles.inputLable}>writeTempFile:</Text>
<Button
title={`${writeTempFile}`}
onPress={() => writeTempFile ? setTempFile(false) : setTempFile(true)}
/>
</View>
<View style={styles.TextInputBox}>
<Text style={styles.inputLable}>includeBase64:</Text>
<Button
title={`${includeBase64}`}
onPress={() => includeBase64 ? setBase64(false) : setBase64(true)}
/>
<Text style={styles.inputLable}>includeExif:</Text>
<Button
title={`${includeExif}`}
onPress={() => includeExif ? setIncludeExif(false) : setIncludeExif(true)}
/>
</View>
<View style={styles.TextInputBox}>
<Text style={styles.inputLable}>avoidEmptySpaceAroundImage :</Text>
<Button
title={`${avoidEmptySpace}`}
onPress={() => avoidEmptySpace ? setAvoidEmptySpace(false) : setAvoidEmptySpace(true)}
/>
</View>
<View style={styles.TextInputBox}>
<Text style={styles.inputLable}>freeStyleCropEnabled :</Text>
<Button
title={`${freeStyleCropEnabled}`}
onPress={() => freeStyleCropEnabled ? setFreeStyleCropEnabled(false) : setFreeStyleCropEnabled(true)}
/>
</View>
<View style={styles.TextInputBox}>
<Text style={styles.inputLable}>forceJpg:</Text>
<Button
title={`${forceJpg}`}
onPress={() => forceJpg ? setForceJpg(false) : setForceJpg(true)}
/>
<Text style={styles.inputLable}>showsSelectedCount:</Text>
<Button
title={`${showsSelectedCount}`}
onPress={() => showsSelectedCount ? setShowsSelectedCount(false) : setShowsSelectedCount(true)}
/>
</View>
<View style={styles.TextInputBox}>
<Text style={styles.inputLable}>mediaType:</Text>
<Button
title='photo'
onPress={() => handleButtonPress('photo')}
accessibilityState={{ selected: selectedButton === 'photo' }}
/>
<Button
title='video'
onPress={() => handleButtonPress('video')}
accessibilityState={{ selected: selectedButton === 'video' }}
/>
<Button
title='any'
onPress={() => handleButtonPress('any')}
accessibilityState={{ selected: selectedButton === 'any' }}
/>
</View>
<View style={styles.TextInputBox}>
<Text style={{color:'red'}}>mediaType is {selectedButton}</Text>
</View>
<View style={styles.TextInputBox}>
<Text style={styles.inputLable}>minFiles:</Text>
<Text style={styles.inputLable}>1</Text>
</View>
<View style={styles.TextInputBox}>
<Text style={styles.inputLable}>maxFiles:</Text>
<TextInput
keyboardType="numeric"
maxLength={1}
style={styles.numberInput}
onChangeText={setMaxFiles}
value={maxFiles}
/>
<Text style={styles.lableType}>(number)</Text>
</View>
<View style={styles.TextInputBox}>
<Text style={styles.inputLable}>compressImageQuality:</Text>
<TextInput
style={styles.numberInput}
onChangeText={setImageQuality}
value={imageQuality}
/>
<Text style={styles.lableType}>(0.1 到 1)</Text>
</View>
<View >
<View style={styles.buttonSty}>
<Button
title='openPicker(打开图库)'
onPress={() => {
openPicker({
multiple: multiple,
writeTempFile: writeTempFile,
includeBase64: includeBase64,
includeExif: includeExif,
avoidEmptySpaceAroundImage: avoidEmptySpace,
freeStyleCropEnabled: freeStyleCropEnabled,
forceJpg: forceJpg,
showsSelectedCount: showsSelectedCount,
mediaType: selectedButton,
minFiles: 1,
maxFiles: maxFiles,
compressImageQuality: imageQuality,
}).then(image => {
console.log(TAG + ' openPicker result ' + JSON.stringify(image))
});
}}
/>
</View>
<View style={styles.TextInputBox}>
<Text style={styles.inputLable}>cropping:</Text>
<Button
title={`${croppingCamera}`}
onPress={() => croppingCamera ? setCroppingCamera(false) : setCroppingCamera(true)}
/>
<Text style={styles.inputLable}>writeTempFile:</Text>
<Button
title={`${writeTempFileCamera}`}
onPress={() => writeTempFileCamera ? setTempFileCamera(false) : setTempFileCamera(true)}
/>
</View>
<View style={styles.TextInputBox}>
<Text style={styles.inputLable}>includeBase64:</Text>
<Button
title={`${includeBase64Camera}`}
onPress={() => includeBase64Camera ? setBase64Camera(false) : setBase64Camera(true)}
/>
<Text style={styles.inputLable}>includeExif:</Text>
<Button
title={`${includeExifCamera}`}
onPress={() => includeExifCamera ? setIncludeExifCamera(false) : setIncludeExifCamera(true)}
/>
</View>
<View style={styles.TextInputBox}>
<Text style={styles.inputLable}>avoidEmptySpaceAroundImage :</Text>
<Button
title={`${avoidEmptySpaceCamera}`}
onPress={() => avoidEmptySpaceCamera ? setAvoidEmptySpaceCamera(false) : setAvoidEmptySpaceCamera(true)}
/>
</View>
<View style={styles.TextInputBox}>
<Text style={styles.inputLable}>freeStyleCropEnabled :</Text>
<Button
title={`${freeStyleCropEnabledCamera}`}
onPress={() => freeStyleCropEnabledCamera ? setFreeStyleCropEnabledCamera(false) : setFreeStyleCropEnabledCamera(true)}
/>
</View>
<View style={styles.TextInputBox}>
<Text style={styles.inputLable}>useFrontCamera:</Text>
<Button
title={`${useFrontCamera}`}
onPress={() => useFrontCamera ? setUseFrontCamera(false) : setUseFrontCamera(true)}
/>
<Text style={styles.inputLable}>forceJpg:</Text>
<Button
title={`${forceJpgCamera}`}
onPress={() => forceJpgCamera ? setForceJpgCamera(false) : setForceJpgCamera(true)}
/>
</View>
<View style={styles.TextInputBox}>
<Text style={styles.inputLable}>mediaType:</Text>
<Button
title='photo'
onPress={() => handleMediaType('photo')}
accessibilityState={{ selected: mediaTypeCamera === 'photo' }}
/>
<Button
title='video'
onPress={() => handleMediaType('video')}
accessibilityState={{ selected: mediaTypeCamera === 'video' }}
/>
<Button
title='any'
onPress={() => handleMediaType('any')}
accessibilityState={{ selected: mediaTypeCamera === 'any' }}
/>
</View>
<View style={styles.TextInputBox}>
<Text style={{ color: 'red' }}>mediaType is {mediaTypeCamera}</Text>
</View>
<View style={styles.TextInputBox}>
<Text style={styles.inputLable}>compressImageQuality:</Text>
<TextInput
style={styles.numberInput}
onChangeText={setImageQualityCamera}
value={imageQualityCamera}
/>
<Text style={styles.lableType}>(0.1 到 1)</Text>
</View>
<View style={styles.TextInputBox}>
<Text style={styles.textLable}>cropperToolbarTitle:</Text>
</View>
<View style={styles.TextInputBox}>
<TextInput
style={styles.textInput}
maxLength={5}
onChangeText={(value) => setCropperTitleCamera(value)}
value={cropperTitleCamera}
/>
</View>
<View style={styles.TextInputBox}>
<Text style={styles.textLable}>cropperChooseText:</Text>
</View>
<View style={styles.TextInputBox}>
<TextInput
style={styles.textInput}
maxLength={5}
onChangeText={(value) => setChooseTextCamera(value)}
value={chooseTextCamera}
/>
</View>
<View style={styles.TextInputBox}>
<Text style={styles.textLable}>cropperChooseColor:例如 #FF0000</Text>
</View>
<View style={styles.TextInputBox}>
<TextInput
style={styles.textInput}
maxLength={7}
onChangeText={(value) => setChooseColorCamera(value)}
value={chooseColorCamera}
/>
</View>
<View style={styles.TextInputBox}>
<Text style={styles.textLable}>cropperCancelText:</Text>
</View>
<View style={styles.TextInputBox}>
<TextInput
style={styles.textInput}
maxLength={5}
onChangeText={(value) => setCancelTextCamera(value)}
value={cancelTextCamera}
/>
</View>
<View style={styles.TextInputBox}>
<Text style={styles.textLable}>cropperCancelColor:例如 #FF0000</Text>
</View>
<View style={styles.TextInputBox}>
<TextInput
style={styles.textInput}
maxLength={7}
onChangeText={(value) => setCancelColorCamera(value)}
value={cancelColorCamera}
/>
</View>
<View style={styles.TextInputBox}>
<Text style={styles.inputLable}>cropperRotateButtonsHidden:</Text>
<Button
title={`${cropperRotateCamera}`}
onPress={() => cropperRotateCamera ? setCropperRotateCamera(false) : setCropperRotateCamera(true)}
/>
</View>
<View style={styles.TextInputBox}>
<Text style={styles.inputLable}>showCropGuidelines:</Text>
<Button
title={`${showCropGuidelinesCamera}`}
onPress={() => showCropGuidelinesCamera ? setShowCropGuidelinesCamera(false) : setShowCropGuidelinesCamera(true)}
/>
</View>
<View style={styles.TextInputBox}>
<Text style={styles.inputLable}>showCropFrame:</Text>
<Button
title={`${showCropFrameCamera}`}
onPress={() => showCropFrameCamera ? setShowCropFrameCamera(false) : setShowCropFrameCamera(true)}
/>
</View>
<View style={styles.buttonSty}>
<Button
title="openCamera (打开相机)"
onPress={() => {
ImagePicker.openCamera({
cropping: croppingCamera,
writeTempFile: writeTempFileCamera,
includeBase64: includeBase64Camera,
includeExif: includeExifCamera,
avoidEmptySpaceAroundImage: avoidEmptySpaceCamera,
freeStyleCropEnabled: freeStyleCropEnabledCamera,
useFrontCamera: useFrontCamera,
forceJpg: forceJpgCamera,
mediaType: mediaTypeCamera,
compressImageQuality: imageQualityCamera,
cropperToolbarTitle: cropperTitleCamera,
cropperChooseText: chooseTextCamera,
cropperChooseColor: chooseColorCamera,
cropperCancelText: cancelTextCamera,
cropperCancelColor: cancelColorCamera,
cropperRotateButtonsHidden: cropperRotateCamera,
showCropGuidelines: showCropGuidelinesCamera,
showCropFrame: showCropFrameCamera,
}).then(image => {
console.log(TAG + ' openCamera result ' + JSON.stringify(image))
});
}}
/>
</View>
<View style={styles.TextInputBox}>
<Text style={styles.textLable}>请输入需要裁剪的图片地址:</Text>
</View>
<View style={styles.TextInputBox}>
<TextInput
style={styles.textInput}
onChangeText={(value) => setImagePath(value)}
value={imagePath}
/>
</View>
<View style={styles.TextInputBox}>
<Text style={styles.inputLable}>writeTempFile:</Text>
<Button
title={`${writeTempFileCropper}`}
onPress={() => writeTempFileCropper ? setTempFileCropper(false) : setTempFileCropper(true)}
/>
<Text style={styles.inputLable}>forceJpg:</Text>
<Button
title={`${forceJpgCropper}`}
onPress={() => forceJpgCropper ? setForceJpgCropper(false) : setForceJpgCropper(true)}
/>
</View>
<View style={styles.TextInputBox}>
<Text style={styles.inputLable}>includeBase64:</Text>
<Button
title={`${includeBase64Cropper}`}
onPress={() => includeBase64Cropper ? setBase64Cropper(false) : setBase64Cropper(true)}
/>
<Text style={styles.inputLable}>includeExif:</Text>
<Button
title={`${includeExifCropper}`}
onPress={() => includeExifCropper ? setIncludeExifCropper(false) : setIncludeExifCropper(true)}
/>
</View>
<View style={styles.TextInputBox}>
<Text style={styles.inputLable}>avoidEmptySpaceAroundImage :</Text>
<Button
title={`${avoidEmptySpaceCropper}`}
onPress={() => avoidEmptySpaceCropper ? setAvoidEmptySpaceCropper(false) : setAvoidEmptySpaceCropper(true)}
/>
</View>
<View style={styles.TextInputBox}>
<Text style={styles.inputLable}>freeStyleCropEnabled :</Text>
<Button
title={`${freeStyleCropEnabledCropper}`}
onPress={() => freeStyleCropEnabledCropper ? setFreeStyleCropEnabledCropper(false) : setFreeStyleCropEnabledCropper(true)}
/>
</View>
<View style={styles.TextInputBox}>
<Text style={styles.inputLable}>compressImageQuality:</Text>
<TextInput
style={styles.numberInput}
onChangeText={setimageQualityCropper}
value={imageQualityCropper}
/>
<Text style={styles.lableType}>(0.1 到 1)</Text>
</View>
<View style={styles.TextInputBox}>
<Text style={styles.textLable}>cropperToolbarTitle:</Text>
</View>
<View style={styles.TextInputBox}>
<TextInput
style={styles.textInput}
maxLength={5}
onChangeText={(value) => setCropperTitle(value)}
value={cropperTitle}
/>
</View>
<View style={styles.TextInputBox}>
<Text style={styles.textLable}>cropperChooseText:</Text>
</View>
<View style={styles.TextInputBox}>
<TextInput
style={styles.textInput}
maxLength={5}
onChangeText={(value) => setChooseText(value)}
value={chooseText}
/>
</View>
<View style={styles.TextInputBox}>
<Text style={styles.textLable}>cropperChooseColor:例如 #FF0000</Text>
</View>
<View style={styles.TextInputBox}>
<TextInput
style={styles.textInput}
maxLength={7}
onChangeText={(value) => setChooseColor(value)}
value={chooseColor}
/>
</View>
<View style={styles.TextInputBox}>
<Text style={styles.textLable}>cropperCancelText:</Text>
</View>
<View style={styles.TextInputBox}>
<TextInput
style={styles.textInput}
maxLength={5}
onChangeText={(value) => setCancelText(value)}
value={cancelText}
/>
</View>
<View style={styles.TextInputBox}>
<Text style={styles.textLable}>cropperCancelColor:例如 #FF0000</Text>
</View>
<View style={styles.TextInputBox}>
<TextInput
style={styles.textInput}
maxLength={7}
onChangeText={(value) => setCancelColor(value)}
value={cancelColor}
/>
</View>
<View style={styles.TextInputBox}>
<Text style={styles.inputLable}>cropperRotateButtonsHidden:</Text>
<Button
title={`${cropperRotate}`}
onPress={() => cropperRotate ? setCropperRotate(false) : setCropperRotate(true)}
/>
</View>
<View style={styles.TextInputBox}>
<Text style={styles.inputLable}>showCropGuidelines:</Text>
<Button
title={`${showCropGuidelines}`}
onPress={() => showCropGuidelines ? setShowCropGuidelines(false) : setShowCropGuidelines(true)}
/>
</View>
<View style={styles.TextInputBox}>
<Text style={styles.inputLable}>showCropFrame:</Text>
<Button
title={`${showCropFrame}`}
onPress={() => showCropFrame ? setShowCropFrame(false) : setShowCropFrame(true)}
/>
</View>
<View style={styles.buttonSty}>
<Button
title='openCropper(打开裁剪)'
onPress={() => {
ImagePicker.openCropper({
path: imagePath,
width: 300,
height: 400,
writeTempFile: writeTempFileCropper,
includeBase64: includeBase64Cropper,
includeExif: includeExifCropper,
avoidEmptySpaceAroundImage: avoidEmptySpaceCropper,
freeStyleCropEnabled: freeStyleCropEnabledCropper,
compressImageQuality: imageQualityCropper,
forceJpg: forceJpgCropper,
cropperToolbarTitle: cropperTitle,
cropperChooseText: chooseText,
cropperChooseColor: chooseColor,
cropperCancelText: cancelText,
cropperCancelColor: cancelColor,
cropperRotateButtonsHidden: cropperRotate,
showCropGuidelines: showCropGuidelines,
showCropFrame: showCropFrame,
}).then((image => {
console.log(TAG + ' openCropper result ' + JSON.stringify(image))
}))
}}
/>
</View>
</View>
</View>
<Text style={styles.title}>清除文件:</Text>
<View style={styles.buttonBox}>
<View style={styles.buttonSty}>
<Button
title='clean (清除所有文件)'
onPress={() => {
ImagePicker.clean({}).then(image => {
console.log(TAG + ' clean result ' + JSON.stringify(image))
});
}}
/>
</View>
<View style={styles.TextInputBox}>
<Text style={styles.textLable}>请输入需要清除图片地址:</Text>
</View>
<View style={styles.TextInputBox}>
<TextInput
style={styles.textInput}
onChangeText={(value) => setClearImagePath(value)}
value={clearImagePath}
/>
</View>
<View style={styles.buttonSty}>
<Button
title='cleanSingle (清除单个文件)'
onPress={() => {
console.log(TAG + " cleanSingle path " + clearImagePath)
ImagePicker.cleanSingle('/data/storage/el2/base/haps/entry/temp/rn_image_crop_picker_lib_temp_' + clearImagePath).then(image => {
})
}}
/>
</View>
<View style={styles.emptyView}></View>
</View>
</ScrollView>
);
}
const styles = StyleSheet.create({
container: {
},
TextInputBox: {
flexDirection: 'row',
alignItems: 'center',
margin: 10,
},
textLable: {
width: '100%'
},
emptyView: {
width: 50,
height: 500
},
inputLable: {
width: 'auto'
},
lableType: {
width: '18%'
},
numberInput: {
width: 50,
height: 30,
color: 'black',
borderColor: 'gray',
borderWidth: 1
},
textInput: {
width: '50%',
height: 36,
color: 'black',
borderColor: 'gray',
bordeWidth: 1
},
switchType: {
width: 60,
height: 36
},
buttonBox: {
marginTop: 20,
},
buttonSty: {
marginTop: 0,
marginRight: 60,
marginBottom: 20,
marginLeft: 60,
textAlign: 'center'
},
title: {
fontWeight: '500',
fontSize: 20,
marginTop: 10,
}
});
export default ImageCropPickDemo;
此步骤为手动配置原生依赖项的指导。
首先需要使用 DevEco Studio 打开项目里的 HarmonyOS 工程 harmony
。
为了让工程依赖同一个版本的 RN SDK,需要在工程根目录的 oh-package.json5
添加 overrides 字段,指向工程需要使用的 RN SDK 版本。替换的版本既可以是一个具体的版本号,也可以是一个模糊版本,还可以是本地存在的 HAR 包或源码目录。
关于该字段的作用请阅读官方说明
{
"overrides": {
"@rnoh/react-native-openharmony": "^0.72.38" // ohpm 在线版本
// "@rnoh/react-native-openharmony" : "./react_native_openharmony.har" // 指向本地 har 包的路径
// "@rnoh/react-native-openharmony" : "./react_native_openharmony" // 指向源码路径
}
}
目前有两种方法:
- 通过 har 包引入(推荐)
- 直接链接源码。
方法一:通过 har 包引入
[!TIP] har 包位于三方库安装路径的
harmony
文件夹下。
打开 entry/oh-package.json5
,添加以下依赖
"dependencies": {
"@rnoh/react-native-openharmony": "file:../react_native_openharmony",
"@react-native-ohos/react-native-image-crop-picker": "file:../../node_modules/@react-native-ohos/react-native-image-crop-picker/harmony/image_crop_picker.har"
}
点击右上角的 sync
按钮
或者在终端执行:
cd entry
ohpm install
方法二:直接链接源码
[!TIP] 如需使用直接链接源码,请参考直接链接源码说明
[!TIP] 版本
0.40.4
及以上需要
打开 entry/src/main/cpp/CMakeLists.txt
,添加:
project(rnapp)
cmake_minimum_required(VERSION 3.4.1)
set(RNOH_APP_DIR "${CMAKE_CURRENT_SOURCE_DIR}")
+ set(OH_MODULES "${CMAKE_CURRENT_SOURCE_DIR}/../../../oh_modules")
set(RNOH_CPP_DIR "${CMAKE_CURRENT_SOURCE_DIR}/../../../../../../react-native-harmony/harmony/cpp")
add_subdirectory("${RNOH_CPP_DIR}" ./rn)
# RNOH_BEGIN: manual_package_linking_1
add_subdirectory("../../../../sample_package/src/main/cpp" ./sample-package)
+ add_subdirectory("${OH_MODULES}/@react-native-ohos/react-native-image-crop-picker/src/main/cpp" ./image-crop-picker)
# RNOH_END: manual_package_linking_1
add_library(rnoh_app SHARED
${GENERATED_CPP_FILES}
+ ${IMAGE_CROP_PICKER_CPP_FILES}
"./PackageProvider.cpp"
"${RNOH_CPP_DIR}/RNOHAppNapiBridge.cpp"
)
target_link_libraries(rnoh_app PUBLIC rnoh)
# RNOH_BEGIN: manual_package_linking_2
target_link_libraries(rnoh_app PUBLIC rnoh_sample_package)
+ target_link_libraries(rnoh_app PUBLIC rnoh_image_crop_picker)
# RNOH_END: manual_package_linking_2
打开 entry/src/main/cpp/PackageProvider.cpp
,添加:
#include "RNOH/PackageProvider.h"
#include "SamplePackage.h"
+ #include "ImageCropPickerPackage.h"
using namespace rnoh;
std::vector<std::shared_ptr<Package>> PackageProvider::getPackages(Package::Context ctx) {
return {
std::make_shared<SamplePackage>(ctx),
+ std::make_shared<ImageCropPickerPackage>(ctx),
};
}
打开 entry/src/main/ets/RNPackagesFactory.ts
,添加:
...
+ import { ImageCropPickerPackage } from '@react-native-ohos/react-native-image-crop-picker/ts';
export function createRNPackages(ctx: RNPackageContext): RNPackage[] {
return [
new SamplePackage(ctx),
+ new ImageCropPickerPackage(ctx),
];
}
(1)在 entry/src/main/ets/entryability 下创建 ImageEditAbility.ets
import UIAbility from '@ohos.app.ability.UIAbility'
import window from '@ohos.window'
const TAG = 'ImageEditAbility';
export default class ImageEditAbility extends UIAbility {
onWindowStageCreate(windowStage: window.WindowStage) {
this.setWindowOrientation(windowStage, window.Orientation.PORTRAIT)
windowStage.loadContent('pages/ImageEdit', (err, data) => {
if (err.code) {
console.info(TAG,'Failed to load the content. Cause: %{public}s',
JSON.stringify(err) ?? '')
return;
}
console.info(TAG,'Succeeded in loading the content')
});
try {
windowStage.getMainWindowSync().setWindowLayoutFullScreen(true, (err)=>{
if (err.code) {
console.error('Failed to enable the full-screen mode. Cause: ' + JSON.stringify(err));
return;
}
console.info('Succeeded in enabling the full-screen mode.');
})
} catch (exception) {
console.error('Failed to set the system bar to be invisible. Cause: ' + JSON.stringify(exception));
}
}
setWindowOrientation(stage: window.WindowStage, orientation: window.Orientation): void {
console.info(TAG,"into setWindowOrientation :")
if (!stage || !orientation) {
return;
}
stage.getMainWindow().then(windowInstance => {
windowInstance.setPreferredOrientation(orientation);
})
}
onBackground() {
this.context.terminateSelf();
}
}
(2)在 entry/src/main/module.json5 注册 ImageEditAbility
"abilities":[{
"name": "ImageEditAbility",
"srcEntry": "./ets/entryability/ImageEditAbility.ets",
"description": "$string:EntryAbility_desc",
"icon": "$media:icon",
"startWindowIcon": "$media:startIcon",
"startWindowBackground": "$color:start_window_background",
"removeMissionAfterTerminate": true,
}
...
]
(3)在 entry/src/main/ets/pages 下创建 ImageEdit.ets
import { ImageEditInfo } from '@react-native-ohos/react-native-image-crop-picker';
@Entry
@Component
struct ImageEdit {
build() {
Row(){
Column(){
ImageEditInfo();
}
.width('100%')
}
.height('100%')
}
}
(4)在 entry/src/main/resources/base/profile/main_pages.json 添加配置
{
"src": [
"pages/Index",
"pages/ImageEdit"
]
}
点击右上角的 sync
按钮
或者在终端执行:
cd entry
ohpm install
然后编译、运行即可。
要使用此库,需要使用正确的 React-Native 和 RNOH 版本。另外,还需要使用配套的 DevEco Studio 和 手机 ROM。
请到三方库相应的 Releases 发布地址查看 Release 配套的版本信息:@react-native-ohos/react-native-image-crop-picker Releases
[!TIP] "Platform"列表示该属性在原三方库上支持的平台。
[!TIP] "HarmonyOS Support"列为 yes 表示 HarmonyOS 平台支持该属性;no 则表示不支持;partially 表示部分支持。使用方法跨平台一致,效果对标 iOS 或 Android 的效果。
Name | Description | Type | Required | Platform | HarmonyOS Support |
---|---|---|---|---|---|
openPicker | Call single image picker with cropping | function | no | iOS/Android | yes |
clean | Module is creating tmp images which are going to be cleaned up automatically somewhere in the future. If you want to force cleanup, you can use clean to clean all tmp files, or cleanSingle(path) to clean single tmp file. |
function | no | iOS/Android | yes |
openCropper | Crop image and rotate, | function | no | iOS/Android | yes |
cleanSingle | Delete a single cache file | function | no | iOS/Android | yes |
openCamera | Select from camera | function | no | iOS/Android | yes |
[!TIP] "Platform"列表示该属性在原三方库上支持的平台。
[!TIP] "HarmonyOS Support"列为 yes 表示 HarmonyOS 平台支持该属性;no 则表示不支持;partially 表示部分支持。使用方法跨平台一致,效果对标 iOS 或 Android 的效果。
cropData
Name | Type | Description | Required | Platform | HarmonyOS Support |
---|---|---|---|---|---|
cropping | bool (default false) | Enable or disable cropping | no | All | yes |
width | number | Width of result image when used with cropping option |
no | All | yes |
height | number | Height of result image when used with cropping option |
no | All | yes |
multiple | bool (default false) | Enable or disable multiple image selection | no | All | yes |
writeTempFile (iOS only) | bool (default true) | When set to false, does not write temporary files for the selected images. This is useful to improve performance when you are retrieving file contents with the includeBase64 option and don't need to read files from disk. |
no | iOS | yes |
includeBase64 | bool (default false) | When set to true, the image file content will be available as a base64-encoded string in the data property. Hint: To use this string as an image source, use it like: <Image source={{uri: data:image.mime;base64,𝑖𝑚𝑎𝑔𝑒.𝑚𝑖𝑚𝑒;𝑏𝑎𝑠𝑒64,{image.data}}} /> |
no | All | yes |
includeExif | bool (default false) | Include image exif data in the response | no | All | yes |
avoidEmptySpaceAroundImage (iOS only) | bool (default true) | When set to true, the image will always fill the mask space. | no | iOS | no |
cropperActiveWidgetColor (Android only) | string (default "#424242" ) |
When cropping image, determines ActiveWidget color. | no | Android | no |
cropperStatusBarColor (Android only) | string (default #424242 ) |
When cropping image, determines the color of StatusBar. | no | Android | no |
cropperToolbarColor (Android only) | string (default #424242 ) |
When cropping image, determines the color of Toolbar. | no | Android | no |
cropperToolbarWidgetColor (Android only) | string (default darker orange ) |
When cropping image, determines the color of Toolbar text and buttons. | no | Android | no |
freeStyleCropEnabled | bool (default false) | Enables user to apply custom rectangle area for cropping | no | All | yes |
cropperToolbarTitle | string (default Edit Photo ) |
When cropping image, determines the title of Toolbar. | no | All | yes |
cropperCircleOverlay | bool (default false) | Enable or disable circular cropping mask. | no | All | no |
disableCropperColorSetters (Android only) | bool (default false) | When cropping image, disables the color setters for cropping library. | no | Android | no |
minFiles (iOS only) | number (default 1) | Min number of files to select when using multiple option |
no | iOS | no |
maxFiles (iOS only) | number (default 5) | Max number of files to select when using multiple option |
no | iOS | yes |
waitAnimationEnd (iOS only) | bool (default true) | Promise will resolve/reject once ViewController completion block is called |
no | iOS | no |
smartAlbums (iOS only) | array (supported values) (default ['UserLibrary', 'PhotoStream', 'Panoramas', 'Videos', 'Bursts']) | List of smart albums to choose from | no | iOS | no |
useFrontCamera | bool (default false) | Whether to default to the front/'selfie' camera when opened. Please note that not all Android devices handle this parameter, see issue #1058 | no | All | yes |
compressVideoPreset (iOS only) | string (default MediumQuality) | Choose which preset will be used for video compression | no | iOS | no |
compressImageMaxWidth | number (default none) | Compress image with maximum width | no | All | no |
compressImageMaxHeight | number (default none) | Compress image with maximum height | no | All | no |
compressImageQuality | number (default 1 (Android)/0.8 (iOS)) | Compress image with quality (from 0 to 1, where 1 is best quality). On iOS, values larger than 0.8 don't produce a noticeable quality increase in most images, while a value of 0.8 will reduce the file size by about half or less compared to a value of 1. | no | All | yes |
loadingLabelText (iOS only) | string (default "Processing assets...") | Text displayed while photo is loading in picker | no | iOS | no |
mediaType | string (default any) | Accepted mediaType for image selection, can be one of: 'photo', 'video', or 'any' | no | All | yes |
showsSelectedCount (iOS only) | bool (default true) | Whether to show the number of selected assets | no | iOS | no |
sortOrder (iOS only) | string (default 'none', supported values: 'asc', 'desc', 'none') | Applies a sort order on the creation date on how media is displayed within the albums/detail photo views when opening the image picker | no | iOS | no |
forceJpg (iOS only) | bool (default false) | Whether to convert photos to JPG. This will also convert any Live Photo into its JPG representation | no | iOS | yes |
showCropGuidelines (Android only) | bool (default true) | Whether to show the 3x3 grid on top of the image during cropping | no | Android | yes |
showCropFrame (Android only) | bool (default true) | Whether to show crop frame during cropping | no | Android | yes |
hideBottomControls (Android only) | bool (default false) | Whether to display bottom controls | no | Android | no |
enableRotationGesture (Android only) | bool (default false) | Whether to enable rotating the image by hand gesture | no | Android | yes |
cropperChooseText (iOS only) | string (default choose) | Choose button text | no | iOS | yes |
cropperChooseColor (iOS only) | string (default #FFCC00 ) |
HEX format color for the Choose button. Default color is controlled by TOCropViewController. | no | iOS | yes |
cropperCancelText (iOS only) | string (default Cancel) | Cancel button text | no | iOS | yes |
cropperCancelColor (iOS only) | string (default tint iOS color ) |
HEX format color for the Cancel button. Default value is the default tint iOS color controlled by TOCropViewController | no | iOS | yes |
cropperRotateButtonsHidden (iOS only) | bool (default false) | Enable or disable cropper rotate buttons | no | iOS | yes |
- react-native-image-crop-picker 图像将始终填充蒙版空间 #4
- Android Demo中 ActiveWidget 改变颜色 #5
- Android Demo中 改变状态栏颜色 #6
- Android Demo中 改变工具栏颜色 #7
- 裁剪图像时,禁用裁剪库的颜色设置器 #8
- 裁剪图像时,确定工具栏文本和按钮的颜色 #9
- 调用ViewController“completion”块,Promise将解析/拒绝, HarmonyOS 不支持 #10
- iOS支持智能相册列表 #11
- iOS视频压缩的预设 #12
- iOS智能相册排序 #13
- Android Demo 设置是否显示底部控件 #14
- 使用multiple选项时无法设置最小文件数 #39
- 使用multiple选项时无法设置是否显示选中的资产数量 #40
- photoAccessHelper选取完成之后没有loading过渡动画效果 #45
- @ohos.multimedia.image无法进行圆形效果裁切 #46
- @ohos.multimedia.image中PackingOption无法设置宽高属性 #47
本项目基于 The MIT License (MIT) ,请自由地享受和参与开源。