译者 | 崔皓

专业领域包括成都网站设计、成都做网站、商城网站定制开发、微信营销、系统平台开发, 与其他网站设计及系统开发公司不同,创新互联建站的整合解决方案结合了帮做网络品牌建设经验和互联网整合营销的理念,并将策略和执行紧密结合,为客户提供全网互联网整合方案。
审校 | 孙淑娟
本文通过分步骤的指南,说明如何在React Native中整合图片编辑,并实现类Instagram滤镜的效果。
在Instagram上,你可以很容易地使用滤镜功能,并迅速得到想要的结果。滤镜功能很好地修改照片,让人们得到想要的效果。一些用户想要在自定义的React Native中实现类似的滤镜效果。也就是说将Instagram的滤镜应用到React Native 程序中。
为了满足这个要求,本文编写了一个分步骤的指南,说明如何在React Native中整合图片编辑,实现类似Instagram滤镜的功能。
我们的开发人员在对React Native中的各种过滤器库进行广泛研究之后,并没有找到理想的实现效果。于是,他们想出了在React Native中构建图像滤镜的特别指南。
就让我们手捧指南,从这里出发吧!
没有特别的要求,只要确保React Native已经安装,并保证项目已经创建。
虽然,安装React Native和设置并非易事,由于本文主题在如何进行图片编辑,因此不展开说React Native和设置,如果有需要可以访问React Native官网,获取更多信息。
在应用程序中,需要三个主要功能;裁剪、过滤和下载。为了实现这些功能,我们的开发人员已经选择了三个最好的库来支持React Native中的滤镜功能。
图像裁剪允许按照尺寸自由调整裁剪图像。它是移动应用开发不可获缺的重要组成部分。我们可以通过Crop Picker Library来获得裁剪图片的功能。该库还提供了视频编辑功能。
我们使用 React Native Image Filter Kit 来处理应用程序中的图像过滤。基于该工具包,我们创建了一个特殊的代码来生成20多个过滤器。
为了分享修改后的图片,人们需要将其下载到手机上。这个功能可以从 React Native Cameraroll Library 库中获得,该库可以帮助开发者将过滤后的图片保存在iOS和Android的照片库中。
一旦上述库安装好之后,就可以开始核心功能的开发了。接下来,让我们进入编码部分,实现既定的里程碑。
如图 1 所示,这里列出了文件夹结构,它可以帮助我们理解文件之间的关系以及需要实现的功能。
图1:代码文件结构
创建文件夹名为 "ChooseImage"。接下来,添加 "index.jsx "文件。为了从手机图库中获取图片,在'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所示内容。
图2:调用手机相册
在第一步中,我们已经在NEXT "按钮上添加了一段代码。因此,当你点击“NEXT”对照片进行裁剪时,就会打开对应的用户界面。用户可以调整图片的大小,也可以旋转它,总之可以对其进行编辑。
选择器提供各种图像比例供用户选取。一旦用户点击了选项按钮,就会出现一个动作表视图。现在,用户可以选择一个预定义的比例对照片进行裁剪了。
现在,选择和裁剪功能已经准备好了。接下来,是时候添加图像过滤功能了。现在让我们创建一个新的文件夹,并命名为Filter Image"。再次,在新文件夹下面创建一个文件
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所示,应用程序的所有过滤器都是可见的了,用户可以选择任意一个滤镜对图片进行处理了。
图 3:图片过滤器应用
完成上述功能之后,接着就需要编写保存/下载图片的功能,否则应用是玩不转的。由于我们在上一步过滤器的基础上添加下载功能的代码。
和前面两个步骤一样,创建一个名为自定义图片。
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;输出结果如图4 所示。
图4:图片下载
根据上述指南,你已经完成了代码的编写。这里对整个指南稍做总结,在保证React Native安装和配置的前提下,分别安装图像裁剪、图像过滤和图片下载的相关库。然后,根据四步实现滤镜功能的开发,包括:调用手机相册、图像裁剪和调整图片大小、创建图像过滤器以及保存和下载图像。
崔皓,社区编辑,资深架构师,拥有18年的软件开发和架构经验,10年分布式架构经验。
原文标题:A Guide to Implement Instagram-Like Filters in React Native,作者:Kiran Beladiya
                网页题目:如何在ReactNative中实现类Instagram滤镜效果?
                
                分享网址:http://www.csdahua.cn/qtweb/news36/133586.html
            
网站建设、网络推广公司-快上网,是专注品牌与效果的网站制作,网络营销seo公司;服务项目有等
声明:本网站发布的内容(图片、视频和文字)以用户投稿、用户转载内容为主,如果涉及侵权请尽快告知,我们将会在第一时间删除。文章观点不代表本网站立场,如需处理请联系客服。电话:028-86922220;邮箱:631063699@qq.com。内容未经允许不得转载,或转载时需注明来源: 快上网