新聞中心
譯者 | 崔皓

專業(yè)領(lǐng)域包括成都網(wǎng)站設(shè)計(jì)、成都做網(wǎng)站、商城網(wǎng)站定制開(kāi)發(fā)、微信營(yíng)銷、系統(tǒng)平臺(tái)開(kāi)發(fā), 與其他網(wǎng)站設(shè)計(jì)及系統(tǒng)開(kāi)發(fā)公司不同,創(chuàng)新互聯(lián)建站的整合解決方案結(jié)合了幫做網(wǎng)絡(luò)品牌建設(shè)經(jīng)驗(yàn)和互聯(lián)網(wǎng)整合營(yíng)銷的理念,并將策略和執(zhí)行緊密結(jié)合,為客戶提供全網(wǎng)互聯(lián)網(wǎng)整合方案。
?審校 | 孫淑娟
開(kāi)篇
本文通過(guò)分步驟的指南,說(shuō)明如何在React Native中整合圖片編輯,并實(shí)現(xiàn)類Instagram濾鏡的效果。
在Instagram上,你可以很容易地使用濾鏡功能,并迅速得到想要的結(jié)果。濾鏡功能很好地修改照片,讓人們得到想要的效果。一些用戶想要在自定義的React Native中實(shí)現(xiàn)類似的濾鏡效果。也就是說(shuō)將Instagram的濾鏡應(yīng)用到React Native 程序中。
為了滿足這個(gè)要求,本文編寫了一個(gè)分步驟的指南,說(shuō)明如何在React Native中整合圖片編輯,實(shí)現(xiàn)類似Instagram濾鏡的功能。
我們的開(kāi)發(fā)人員在對(duì)React Native中的各種過(guò)濾器庫(kù)進(jìn)行廣泛研究之后,并沒(méi)有找到理想的實(shí)現(xiàn)效果。于是,他們想出了在React Native中構(gòu)建圖像濾鏡的特別指南。
就讓我們手捧指南,從這里出發(fā)吧!
前提條件
沒(méi)有特別的要求,只要確保React Native已經(jīng)安裝,并保證項(xiàng)目已經(jīng)創(chuàng)建。
雖然,安裝React Native和設(shè)置并非易事,由于本文主題在如何進(jìn)行圖片編輯,因此不展開(kāi)說(shuō)React Native和設(shè)置,如果有需要可以訪問(wèn)??React Native官網(wǎng)??,獲取更多信息。
安裝相關(guān)庫(kù)
在應(yīng)用程序中,需要三個(gè)主要功能;裁剪、過(guò)濾和下載。為了實(shí)現(xiàn)這些功能,我們的開(kāi)發(fā)人員已經(jīng)選擇了三個(gè)最好的庫(kù)來(lái)支持React Native中的濾鏡功能。
1.圖像裁剪
圖像裁剪允許按照尺寸自由調(diào)整裁剪圖像。它是移動(dòng)應(yīng)用開(kāi)發(fā)不可獲缺的重要組成部分。我們可以通過(guò)??Crop Picker Library??來(lái)獲得裁剪圖片的功能。該庫(kù)還提供了視頻編輯功能。
2.圖像過(guò)濾器
我們使用 ??React Native Image Filter Kit?? 來(lái)處理應(yīng)用程序中的圖像過(guò)濾?;谠摴ぞ甙覀儎?chuàng)建了一個(gè)特殊的代碼來(lái)生成20多個(gè)過(guò)濾器。
3.圖片下載
為了分享修改后的圖片,人們需要將其下載到手機(jī)上。這個(gè)功能可以從 ??React Native Cameraroll Library?? 庫(kù)中獲得,該庫(kù)可以幫助開(kāi)發(fā)者將過(guò)濾后的圖片保存在iOS和Android的照片庫(kù)中。
核心功能開(kāi)發(fā)指南
一旦上述庫(kù)安裝好之后,就可以開(kāi)始核心功能的開(kāi)發(fā)了。接下來(lái),讓我們進(jìn)入編碼部分,實(shí)現(xiàn)既定的里程碑。
如圖 1 所示,這里列出了文件夾結(jié)構(gòu),它可以幫助我們理解文件之間的關(guān)系以及需要實(shí)現(xiàn)的功能。
圖1:代碼文件結(jié)構(gòu)
第1步:調(diào)用手機(jī)相冊(cè)
創(chuàng)建文件夾名為 "ChooseImage"。接下來(lái),添加 "index.jsx "文件。為了從手機(jī)圖庫(kù)中獲取圖片,在'index.jsx'文件中添加以下代碼。
import React, { useState } from 'react';
import {
Image,
Alert,
SafeAreaView,
StyleSheet,
Text,
TouchableOpacity,
View,
} from 'react-native';
import { launchImageLibrary } from 'react-native-image-picker';
import {
widthPercentageToDP as wp,
heightPercentageToDP as hp,
} from 'react-native-responsive-screen';
import Constants from '../../Constants/Constants';
import Button from '../../Components/Button';
import Loader from '../../Components/Loader';
import ImagePicker from 'react-native-image-crop-picker';
const CreatePost = ({ navigation }) => {
const [thumbnail, setThumbnail] = useState({});
const [loaderVisible, setLoaderVisible] = useState(false);
const onChooseImage = async (selectionType) => {
const options = {
cameraType: 'back',
mediaType: selectionType,
includeBase64: true,
};
const result = await launchImageLibrary(options);
if (!result.didCancel && result.assets) {
if (selectionType === 'photo') {
const photoData = {
uri: result.assets[0].uri,
type: result.assets[0].type,
name: result.assets[0].fileName,
};
setThumbnail(photoData);
}
}
if (result.errorMessage) console.log('error');
};
const handleNextStepClick = async () => {
if (!thumbnail.length) {
setLoaderVisible(false);
if (!Object.keys(thumbnail).length) {
Alert.alert('Please add thumbnail image');
return;
} else {
return ImagePicker.openCropper({
includeBase64: true,
path: thumbnail,
cropping: false,
freeStyleCropEnabled: true,
compressImageQuality: 0.8,
showCropFrame: true,
mediaType: 'photo',
}).then(image => {
navigation.navigate('FilterScreen', { imageData: image });
})
}
}
};
return (
style={styles.safeView}>
style={styles.imageView}>
{Object.keys(thumbnail).length ? (
<>
style={styles.insideView}>
source={{ uri: thumbnail?.uri }}
style={styles.thumbImage}
resizeMode={'contain'}
/>
style={styles.editView}>
activeOpacity={0.6}
onPress={() => onChooseImage('photo')}
style={{
...styles.addLessonBtnContainer,
marginEnd: 7,
}}>
source={require('../../Assests/icon_edit.png')}
resizeMode="contain"
style={styles.editImage}
/>
activeOpacity={0.6}
onPress={() => setThumbnail({})}
style={styles.addLessonBtnContainer}>
source={require('../../Assests/delete.png')}
resizeMode="contain"
style={styles.editImage}
/>
>
) : (
<>
onPress={() => onChooseImage('photo')}
activeOpacity={0.7}>
source={require('../../Assests/Pick.png')}
style={styles.galleryImg}
resizeMode="contain"
/>
style={styles.postTextView}>
{Constants.create_post_story}
>
)}
);
};
const styles = StyleSheet.create({
button_next: {
textTransform: 'uppercase',
fontSize: wp('5%'),
color: 'white',
marginHorizontal: wp('7%')
},
editView: {
justifyContent: 'flex-end',
alignItems: 'center',
marginTop: wp('5%'),
alignSelf: 'flex-end',
display: 'flex',
flexDirection: 'row',
},
imageView: {
paddingHorizontal: wp('5%'),
paddingVertical: wp('10%'),
backgroundColor: '#FFFFFF',
marginTop: wp('5%'),
width: wp('100%'),
},
insideView: {
width: '100%',
justifyContent: 'center',
alignItems: 'center',
},
thumbImage: {
width: wp('100%'),
height: wp('80%'),
},
editImage: {
width: wp('4.5%'),
height: wp('4.5%'),
tintColor: '#FFFFFF',
},
galleryView: {
height: wp('20%'),
width: wp('20%'),
backgroundColor: '#FF701F',
borderRadius: 40,
justifyContent: 'center',
alignItems: 'center'
},
galleryImg: {
height: wp('7%'),
width: wp('7%'),
tintColor: 'white'
},
postTextView: {
marginTop: wp('5%'),
},
safeView: {
flex: 1,
backgroundColor: '#fff',
},
buttonView: {
marginTop: wp('7%'),
marginBottom: wp('3%')
},
pickContainer: {
borderWidth: 1,
borderColor: '#DFDFDF',
marginTop: hp('10%'),
justifyContent: 'center',
alignItems: 'center',
borderStyle: 'dashed',
width: '100%',
paddingVertical: wp('7%'),
},
addLessonBtnContainer: {
backgroundColor: '#FF701F',
borderRadius: 4,
paddingHorizontal: wp('3%'),
paddingVertical: wp('2%'),
},
introText: {
textTransform: 'uppercase',
textAlign: 'center',
textAlignVertical: 'center',
color: '#1F1F1F',
fontSize: wp('5%'),
},
});
export default CreatePost;輸出
一旦完成上述代碼,并將其添加到之后,你就可以看到如圖2所示內(nèi)容。
圖2:調(diào)用手機(jī)相冊(cè)
第2步:圖像裁剪和調(diào)整大小
在第一步中,我們已經(jīng)在NEXT "按鈕上添加了一段代碼。因此,當(dāng)你點(diǎn)擊“NEXT”對(duì)照片進(jìn)行裁剪時(shí),就會(huì)打開(kāi)對(duì)應(yīng)的用戶界面。用戶可以調(diào)整圖片的大小,也可以旋轉(zhuǎn)它,總之可以對(duì)其進(jìn)行編輯。
選擇器提供各種圖像比例供用戶選取。一旦用戶點(diǎn)擊了選項(xiàng)按鈕,就會(huì)出現(xiàn)一個(gè)動(dòng)作表視圖?,F(xiàn)在,用戶可以選擇一個(gè)預(yù)定義的比例對(duì)照片進(jìn)行裁剪了。
第3步:創(chuàng)建圖像過(guò)濾器
現(xiàn)在,選擇和裁剪功能已經(jīng)準(zhǔn)備好了。接下來(lái),是時(shí)候添加圖像過(guò)濾功能了?,F(xiàn)在讓我們創(chuàng)建一個(gè)新的文件夾,并命名為Filter Image"。再次,在新文件夾下面創(chuàng)建一個(gè)文件
import React, { useRef, useState, useEffect } from 'react';
import {
widthPercentageToDP as wp,
heightPercentageToDP as hp,
} from 'react-native-responsive-screen';
import {
FlatList,
Image,
SafeAreaView,
StyleSheet,
Text,
TouchableOpacity,
ImageBackground,
View,
} from 'react-native';
import { FILTERS } from '../../Helpers/Filters';
import Button from '../../Components/Button';
import Constants from '../../Constants/Constants';
import { KeyboardAwareScrollView } from 'react-native-keyboard-aware-scroll-view';
const FilterScreen = ({ navigation, route }) => {
const [selectedFilterIndex, setIndex] = useState(0);
const [image, SetImage] = useState('')
const [thumbnail, setThumbnail] = useState({});
useEffect(() => {
getImageFromNavigation()
})
const getImageFromNavigation = () => {
if (route?.params?.imageData) {
setThumbnail(route?.params?.imageData)
}
}
const onExtractImage = ({ nativeEvent }) => {
SetImage(nativeEvent.uri)
extractedUri.current = nativeEvent.uri;
};
const onSelectFilter = selectedIndex => {
setIndex(selectedIndex);
};
const extractedUri = useRef(thumbnail?.path);
const handleNextStepClick = async () => {
if (selectedFilterIndex === 0) {
navigation.navigate('ViewImage', { imageString: thumbnail })
} else {
console.log('goinfFromHere');
navigation.navigate('ViewImage', { imageString: image })
}
};
const renderFilterComponent = ({ item, index }) => {
const FilterComponent = item.filterComponent;
const image = (
style={styles.filterSelector}
source={{ uri: thumbnail?.path }}
defaultSource={require('../../Assests/Pick.png')}
/>
);
return (
onSelectFilter(index)}>
{item.title}
);
};
const SelectedFilterComponent = FILTERS[selectedFilterIndex].filterComponent;
return (
<>
style={styles.safeView}>
source={require('../../Assests/image_background.png')}
style={styles.container}>
contentContainerStyle={styles.keyboardContainer}
resetScrollToCoords={{ x: 0, y: 0 }}>
{selectedFilterIndex === 0 ? (
style={styles.default_Img}
source={{ uri: thumbnail?.path }}
resizeMode='contain'
/>
) : Object.keys(thumbnail).length && (
onExtractImage={onExtractImage}
extractImageEnabled={true}
image={
style={styles.default_Img}
source={{ uri: thumbnail?.path }}
resizeMode='contain'
/>
}
/>
)}
data={FILTERS}
keyExtractor={item => item.title}
showsHorizontalScrollIndicator={false}
horizontal={true}
renderItem={renderFilterComponent}
/>
>
);
};
const styles = StyleSheet.create({
default_Img: {
flex: 1,
width: wp('100%'),
height: hp('50%'),
alignSelf: 'center',
alignContent: 'center'
},
keyboardContainer: {
width: wp('90%'),
},
buttonView: {
marginTop: wp('7%'),
marginBottom: wp('3%')
},
safeView: {
flex: 1,
backgroundColor: '#fff',
},
filterSelector: {
width: 100,
height: 100,
margin: 5,
},
filterTitle: {
marginTop: 70,
fontSize: 12,
textAlign: 'center',
},
container: {
flex: 1,
justifyContent: 'center',
backgroundColor: '#FFFFFF',
alignItems: 'center',
},
});
export default FilterScreen;輸出
完成上述代碼之后,如圖3所示,應(yīng)用程序的所有過(guò)濾器都是可見(jiàn)的了,用戶可以選擇任意一個(gè)濾鏡對(duì)圖片進(jìn)行處理了。
圖 3:圖片過(guò)濾器應(yīng)用
第4步:圖像保存和下載
完成上述功能之后,接著就需要編寫保存/下載圖片的功能,否則應(yīng)用是玩不轉(zhuǎn)的。由于我們?cè)谏弦徊竭^(guò)濾器的基礎(chǔ)上添加下載功能的代碼。
和前面兩個(gè)步驟一樣,創(chuàng)建一個(gè)名為自定義圖片。
import React, { useState, useEffect } from 'react';
import {
View,
StyleSheet,
Image,
Platform,
PermissionsAndroid
} from 'react-native';
import { CameraRoll } from "@react-native-camera-roll/camera-roll";
import {
widthPercentageToDP as wp,
heightPercentageToDP as hp,
} from 'react-native-responsive-screen';
import Constants from '../../Constants/Constants';
import Button from '../../Components/Button';
const ViewImage = ({ route }) => {
const [thumbnail, setThumbnail] = useState({});
const [photos, setPhotos] = useState('');
useEffect(() => {
getImageFromNavigation()
})
const getImageFromNavigation = () => {
if (route?.params?.imageString) {
console.log('params-->', route?.params?.imageString);
setThumbnail(route?.params?.imageString)
setPhotos(route?.params?.imageString)
}
}
async function hasAndroidPermission() {
const permission = PermissionsAndroid.PERMISSIONS.WRITE_EXTERNAL_STORAGE;
const hasPermission = await PermissionsAndroid.check(permission);
if (hasPermission) {
return true;
}
const status = await PermissionsAndroid.request(permission);
return status === 'granted';
}
async function savePicture() {
if (Platform.OS === "android" && !(await hasAndroidPermission())) {
return;
}
CameraRoll.save(photos, { type: 'photo' })
};
return (
source={{ uri: photos !== '' ? photos : thumbnail?.path }}
style={styles.imgView}
/>
);
};
const styles = StyleSheet.create({
imgView: {
width: wp('100%'),
height: hp('30%'),
resizeMode: 'contain'
},
container: {
flex: 1,
alignItems: 'center',
backgroundColor: '#F5FCFF',
paddingTop: 30,
marginVertical: hp('25%')
},
buttonView: {
marginTop: wp('7%'),
marginBottom: wp('3%'),
width: wp('80%'),
},
});
export default ViewImage;輸出結(jié)果如圖4 所示。
圖4:圖片下載
總結(jié)
根據(jù)上述指南,你已經(jīng)完成了代碼的編寫。這里對(duì)整個(gè)指南稍做總結(jié),在保證React Native安裝和配置的前提下,分別安裝圖像裁剪、圖像過(guò)濾和圖片下載的相關(guān)庫(kù)。然后,根據(jù)四步實(shí)現(xiàn)濾鏡功能的開(kāi)發(fā),包括:調(diào)用手機(jī)相冊(cè)、圖像裁剪和調(diào)整圖片大小、創(chuàng)建圖像過(guò)濾器以及保存和下載圖像。
譯者介紹
崔皓,社區(qū)編輯,資深架構(gòu)師,擁有18年的軟件開(kāi)發(fā)和架構(gòu)經(jīng)驗(yàn),10年分布式架構(gòu)經(jīng)驗(yàn)。
原文標(biāo)題:??A Guide to Implement Instagram-Like Filters in React Native??,作者:Kiran Beladiya
當(dāng)前文章:如何在ReactNative中實(shí)現(xiàn)類Instagram濾鏡效果?
本文網(wǎng)址:http://fisionsoft.com.cn/article/ccdpsji.html


咨詢
建站咨詢
