UNPKG

react-native-img-browser

Version:

此组件基于react-native-photo-browser@0.4.0进行修改,主要修复其大量图片时,滑动动画不流畅;图片多时打开大图加载卡顿或加载不出来,将react-native-photo-browser中的FullScreenContainer文件中的ListView组件替换成FlatList组件

281 lines (242 loc) 7.38 kB
import React, { Component } from 'react'; import PropTypes from 'prop-types'; import { Dimensions, Image, StyleSheet, View, TouchableWithoutFeedback, ActivityIndicator, Platform, } from 'react-native'; import * as Progress from 'react-native-progress-cus'; export default class Photo extends Component { static propTypes = { /* * image uri or opaque type that is passed as source object to image component */ uri: PropTypes.oneOfType([ // assets or http url PropTypes.string, // Opaque type returned by require('./image.jpg') PropTypes.number, ]).isRequired, /* * displays a check button above the image */ displaySelectionButtons: PropTypes.bool, /* * image resizeMode */ resizeMode: PropTypes.string, /* * these values are set to image and it's container * screen width and height are used if those are not defined */ width: PropTypes.number, height: PropTypes.number, /* * when lazyLoad is true, * image is not loaded until 'load' method is manually executed */ lazyLoad: PropTypes.bool, /* * displays selected or unselected icon based on this prop */ selected: PropTypes.bool, /* * size of selection images are decided based on this */ thumbnail: PropTypes.bool, /* * executed when user selects/unselects the photo */ onSelection: PropTypes.func, /* * image tag generated using require(asset_path) */ progressImage: PropTypes.number, /* * displays Progress.Circle instead of default Progress.Bar * it's ignored when progressImage is also passed. * iOS only */ useCircleProgress: PropTypes.bool, }; static defaultProps = { resizeMode: 'contain', thumbnail: false, lazyLoad: false, selected: false, }; constructor(props) { super(props); this._onProgress = this._onProgress.bind(this); this._onError = this._onError.bind(this); this._onLoad = this._onLoad.bind(this); this._toggleSelection = this._toggleSelection.bind(this); const { lazyLoad, uri } = props; this.state = { uri: lazyLoad ? null : uri, progress: 0, error: false, }; } load() { if (!this.state.uri) { this.setState({ uri: this.props.uri, }); } } _onProgress(event) { const progress = event.nativeEvent.loaded / event.nativeEvent.total; if (!this.props.thumbnail && progress !== this.state.progress) { this.setState({ progress, }); } } _onError() { this.setState({ error: true, progress: 1, }); } _onLoad() { this.setState({ progress: 1, }); } _toggleSelection() { // onSelection is resolved in index.js // and refreshes the dataSource with new media object this.props.onSelection(!this.props.selected); } _renderProgressIndicator() { const { progressImage, useCircleProgress } = this.props; const { progress } = this.state; // return null; if (progress < 1) { if (progressImage) { return ( <Image source={progressImage} /> ); } if (Platform.OS === 'android') { return <ActivityIndicator animating={ true }/>; } const ProgressElement = useCircleProgress ? Progress.Circle : Progress.Bar; return ( <ProgressElement progress={progress} thickness={20} color={'white'} /> ); } return null; } _renderErrorIcon() { return ( <Image source={require('../../Assets/image-error.png')} /> ); } _renderSelectionButton() { const { progress } = this.state; const { displaySelectionButtons, selected, thumbnail } = this.props; // do not display selection before image is loaded if (!displaySelectionButtons || progress < 1) { return null; } let buttonImage; if (thumbnail) { let icon = require('../../Assets/small-selected-off.png'); if (selected) { icon = require('../../Assets/small-selected-on.png'); } buttonImage = ( <Image source={icon} style={styles.thumbnailSelectionIcon} /> ); } else { let icon = require('../../Assets/selected-off.png'); if (selected) { icon = require('../../Assets/selected-on.png'); } buttonImage = ( <Image style={styles.fullScreenSelectionIcon} source={icon} /> ); } return ( <TouchableWithoutFeedback onPress={this._toggleSelection}> {buttonImage} </TouchableWithoutFeedback> ); } render() { const { resizeMode, width, height } = this.props; const screen = Dimensions.get('window'); const { uri, error } = this.state; let source; if (uri) { // create source objects for http/asset strings // or directly pass uri number for local files source = typeof uri === 'string' ? { uri } : uri; } // i had to get window size and set photo size here // to be able to respond device orientation changes in full screen mode // FIX_ME: when you have a better option const sizeStyle = { width: width || screen.width, height: height || screen.height, }; return ( <View style={[styles.container, sizeStyle]}> {error ? this._renderErrorIcon() : this._renderProgressIndicator()} <Image {...this.props} style={[styles.image, sizeStyle]} source={source} onProgress={this._onProgress} onError={this._onError} onLoad={this._onLoad} resizeMode={resizeMode} /> {this._renderSelectionButton()} </View> ); } } const styles = StyleSheet.create({ container: { alignItems: 'center', justifyContent: 'center', }, image: { position: 'absolute', top: 0, left: 0, right: 0, bottom: 0, }, thumbnailSelectionIcon: { position: 'absolute', top: 8, right: 8, }, fullScreenSelectionIcon: { position: 'absolute', top: 60, right: 16, }, });