UNPKG

react-native-stickers

Version:

Fully customizable image sticker editor for react native

258 lines (239 loc) 6.63 kB
import React, {Component} from 'react'; import ViewShot from 'react-native-view-shot'; //Native import { Animated, Dimensions, Image, ImageBackground, Modal, PanResponder, ScrollView, StyleSheet, TouchableOpacity, Text, View } from 'react-native'; const ghost = require('./emojis/ghost.png'); const heart = require('./emojis/heart.png'); const heartEyes = require('./emojis/heartEyes.png'); const kiss = require('./emojis/kiss.png'); const party = require('./emojis/party.png'); const robot = require('./emojis/robot.png'); const smile = require('./emojis/smile.png'); const sunglasses = require('./emojis/sunglasses.png'); const thumbsup = require('./emojis/thumbsup.png'); type Props = {}; export default class StickerPicker extends Component<Props> { constructor(props) { super(props); this.state = { pan: new Animated.ValueXY(), showSticker: false, }; this.panResponder = PanResponder.create({ onStartShouldSetPanResponder: () => true, onPanResponderMove: Animated.event([ null, { dx: this.state.pan.x, dy: this.state.pan.y, }, ]), onPanResponderRelease: (e, gesture) => { this.state.pan.setOffset( { x: this.currentPanValue.x, y: this.currentPanValue.y } ); this.state.pan.setValue( { x: 0, y: 0 } ); }, }); } componentDidMount() { this._isMounted = true; if(this._isMounted) { this.currentPanValue = {x: 0, y: 0}; this.panListener = this.state.pan.addListener((value) => this.currentPanValue = value); } } componentWillUnmount() { if(this._isMounted) { this.state.pan.removeListener(this.panListener); } this._isMounted = false; } takeViewShot() { if(this._isMounted) { this.viewShot.capture().then(uri => { Image.getSize(uri, (width, height) => { this.props.completedEditing(uri, width, height); this.setState({ finalImage: { uri: uri, width: width, height: height } }) }); }); } } resetViewShot() { if(this._isMounted) { this.setState({ finalImage: null, pan: new Animated.ValueXY(), showSticker: false, }) } } previewStickerImage(imageUrl, size = 15) { if(this._isMounted) { return( <Image style={{width: this.props.previewImageSize, height: this.props.previewImageSize, margin: 5}} source={imageUrl} /> ) } } render() { const { bottomContainer, bottomContainerStyle, imageSource, includeDefaultStickers, stickers, style, topContainer, visible } = this.props; const { finalImage, showSticker, sticker } = this.state; const finalImageUrl = finalImage ? finalImage.uri : null; const defaultStickers = [ [ this.previewStickerImage(ghost), ghost ], [ this.previewStickerImage(heart), heart ], [ this.previewStickerImage(heartEyes), heartEyes ], [ this.previewStickerImage(kiss), kiss ], [ this.previewStickerImage(party), party ], [ this.previewStickerImage(robot), robot ], [ this.previewStickerImage(smile), smile ], [ this.previewStickerImage(sunglasses), sunglasses ], [ this.previewStickerImage(thumbsup), thumbsup ] ]; let finalStickers; if(!stickers) { finalStickers = defaultStickers; } else if(includeDefaultStickers) { finalStickers = stickers.concat(defaultStickers); } else { finalStickers = stickers; } if(!this._isMounted) { return <View /> } return ( <Modal visible={visible}> <View> { topContainer } </View> <View> { !finalImage && ( <View> <ViewShot style={{ flex: null}} ref={ref => { this.viewShot = ref; }} options={{ format: 'jpg', quality: 1.0 }} > <ImageBackground ref={image => (this.imageComponent = image)} source={{ uri: imageSource }} style={[styles.attachment, this.props.imageStyle]} > { showSticker && this._isMounted && ( <Animated.View {...this.panResponder.panHandlers} style={[this.state.pan.getLayout()]} > <Image style={{width: this.props.stickerSize, height: this.props.stickerSize}} source={sticker} /> </Animated.View> )} </ImageBackground> </ViewShot> <Text style={styles.title}>Select a sticker</Text> <ScrollView overScrollMode={'always'} horizontal={true} contentContainerStyle={[styles.stickerPickerContainer, this.props.bottomContainerStyle]}> {finalStickers.map((sticker, index) => { return( <TouchableOpacity key={index} onPress={() => this._isMounted && this.setState({showSticker: true, sticker: sticker[1]})}> {sticker[0]} </TouchableOpacity> ) })} </ScrollView> <TouchableOpacity style={this.props.bottomContainerStyle} onPress={() => this.takeViewShot()}> {bottomContainer} </TouchableOpacity> </View> )} </View> </Modal> ); } } let { height, width } = Dimensions.get('window'); const styles = StyleSheet.create({ stickerPickerContainer: { flexDirection: 'row', flexWrap: 'wrap', width: width, alignItems: 'center', justifyContent: 'center', minHeight: 150, }, actionTitle: { color:'blue', alignSelf: 'center', marginTop: 20, fontSize: 20 }, attachment: { alignItems: 'center', justifyContent: 'center', alignSelf: 'stretch', height: 500, width: width, }, finalAttachment: { alignItems: 'center', justifyContent: 'center', alignSelf: 'stretch', height: 500, width: width, }, text: { fontSize: 15, alignSelf: 'center', marginLeft: 5, marginRight: 5, textAlign: 'center', color: '#fff', }, title: { width: width, marginVertical: 5, fontSize: 20, textAlign: 'center' }, });