react-native-image-layout
Version:
An easy and simple to use React Native component to render a custom masonry layout for remote/local images and displayed on a custom interactive image viewer. Includes animations and support for both iOS and Android. Free and made possible along with co
313 lines (304 loc) • 11 kB
JavaScript
import React from "react";
import { Platform, Image, Dimensions, View } from "react-native";
import GallerySwiper from "react-native-gallery-swiper";
import SmartGallery from "react-native-smart-gallery";
import PropTypes from "prop-types";
import DefaultHeader from "./DefaultHeader";
import PageHeader from "./PageHeader";
import PageFooter from "./PageFooter";
export default class ImageViewer extends React.PureComponent {
static propTypes = {
images: PropTypes.array.isRequired,
imageId: PropTypes.string.isRequired,
galleryInitialIndex: PropTypes.number.isRequired,
galleryIndex: PropTypes.number.isRequired,
onClose: PropTypes.func.isRequired,
onChangePhoto: PropTypes.func.isRequired,
// Gallery props
imagePageComponent: PropTypes.func,
errorPageComponent: PropTypes.func,
pagesFlatListProps: PropTypes.object,
pageMargin: PropTypes.number,
sensitivePageScroll: PropTypes.bool,
onPageSelected: PropTypes.func,
onPageScrollStateChanged: PropTypes.func,
onPageScroll: PropTypes.func,
pageScrollViewStyle: PropTypes.object,
onPageSingleTapConfirmed: PropTypes.func,
onPageLongPress: PropTypes.func,
renderPageHeader: PropTypes.func,
renderPageFooter: PropTypes.func,
onDoubleTapConfirmed: PropTypes.func,
onDoubleTapStartReached: PropTypes.func,
onDoubleTapEndReached: PropTypes.func,
onPinchTransforming: PropTypes.func,
onPinchStartReached: PropTypes.func,
onPinchEndReached: PropTypes.func,
enableScale: PropTypes.bool,
enableTranslate: PropTypes.bool,
resizeMode: PropTypes.string,
enableResistance: PropTypes.bool,
resistantStrHorizontal: PropTypes.oneOfType([
PropTypes.func,
PropTypes.number,
PropTypes.string
]),
resistantStrVertical: PropTypes.oneOfType([
PropTypes.func,
PropTypes.number,
PropTypes.string
]),
onViewTransformed: PropTypes.func,
onTransformGestureReleased: PropTypes.func,
onSwipeUpReleased: PropTypes.func,
onSwipeDownReleased: PropTypes.func,
maxScale: PropTypes.number,
maxOverScrollDistance: PropTypes.number,
enableVerticalExit: PropTypes.bool,
enableModal: PropTypes.bool,
onEndReached: PropTypes.func,
onEndReachedThreshold: PropTypes.number,
}
constructor(props) {
super(props);
this.state = {
width: Dimensions.get("window").width,
height: Dimensions.get("window").height,
};
}
_handleVerticalSwipe = (transform) => {
const { scale, translateY: y } = transform;
if (scale === 1 && (y < -150 || y > 150)) {
this.props.onClose();
}
}
_renderIOSVerticalScrollView(
width,
height,
imageSource
) {
const {
renderPageHeader, renderPageFooter,
images, onClose, enableModal
} = this.props;
return (
<View style={{ width, height }}>
{
renderPageHeader
? <PageHeader
renderPageHeader={renderPageHeader}
image={imageSource}
galleryIndex={imageSource.index}
onClose={onClose}
/>
: enableModal
? <DefaultHeader
onClose={onClose}
/>
: null
}
<GallerySwiper
style={{ flex: 1, backgroundColor: "black" }}
images={images}
initialPage={this.props.galleryInitialIndex}
initialNumToRender={this.props.images.length}
errorComponent={this.props.errorPageComponent}
flatListProps={this.props.pagesFlatListProps}
pageMargin={this.props.pageMargin}
sensitiveScroll={this.props.sensitivePageScroll}
onPageScrollStateChanged={this.props.onPageScrollStateChanged}
onPageScroll={this.props.onPageScroll}
scrollViewStyle={this.props.pageScrollViewStyle}
onSingleTapConfirmed={this.props.onPageSingleTapConfirmed}
onLongPress={this.props.onPageLongPress}
imageComponent={(imageProps, imageDimensions, index) => {
if (!this.props.imagePageComponent) {
return <Image {...imageProps} />;
} else {
return this.props.imagePageComponent(imageProps, imageDimensions, index);
}
}}
onPageSelected={(index) => {
this.props.onChangePhoto(images[index].id, index);
this.props.onPageSelected &&
this.props.onPageSelected(index);
}}
onPinchTransforming={(transform, i) => {
if (this.props.onPinchTransforming) {
this.props.onPinchTransforming(transform, i);
}
}}
onPinchStartReached={(transform, i) => {
if (this.props.onPinchStartReached) {
this.props.onPinchStartReached(transform, i);
}
}}
onDoubleTapStartReached={(transform, i) => {
if (this.props.onDoubleTapStartReached) {
this.props.onDoubleTapStartReached(transform, i);
}
}}
onDoubleTapEndReached={(transform, i) => {
if (this.props.onDoubleTapEndReached) {
this.props.onDoubleTapEndReached(transform, i);
}
}}
onDoubleTapConfirmed={this.props.onDoubleTapConfirmed}
onPinchEndReach={this.props.onPinchEndReach}
enableScale={this.props.enableScale}
enableTranslate={this.props.enableTranslate}
resizeMode={this.props.resizeMode}
enableResistance={this.props.enableResistance}
resistantStrHorizontal={this.props.resistantStrHorizontal}
resistantStrVertical={this.props.resistantStrVertical}
onViewTransformed={this.props.onViewTransformed}
onTransformGestureReleased={(transform, i) => {
if (this.props.enableVerticalExit) {
this._handleVerticalSwipe(transform);
}
if (this.props.onTransformGestureReleased) {
this.props.onTransformGestureReleased(transform, i);
}
}}
onSwipeUpReleased={(transform, i) => {
this.props.onSwipeUpReleased &&
this.props.onSwipeUpReleased(transform, i);
}}
onSwipeDownReleased={(transform, i) => {
this.props.onSwipeDownReleased &&
this.props.onSwipeDownReleased(transform, i);
}}
maxScale={this.props.maxScale}
maxOverScrollDistance={this.props.maxOverScrollDistance}
onEndReached={this.props.onEndReached}
onEndReachedThreshold={this.props.onEndReachedThreshold}
/>
{
renderPageFooter &&
<PageFooter
renderPageFooter={renderPageFooter}
image={imageSource}
galleryIndex={imageSource.index}
onClose={onClose}
/>
}
</View>
);
}
_renderAndroidVerticalView(
width,
height,
imageSource
) {
const {
renderPageHeader, renderPageFooter,
images, onClose, enableModal
} = this.props;
return (
<View style={{ width, height }}>
{
renderPageHeader
? <PageHeader
renderPageHeader={renderPageHeader}
image={imageSource}
galleryIndex={imageSource.index}
onClose={onClose}
/>
: enableModal
? <DefaultHeader
onClose={onClose}
/>
: null
}
<SmartGallery
images={images}
index={this.props.galleryInitialIndex}
errorComponent={this.props.errorPageComponent}
pageMargin={this.props.pageMargin}
sensitiveScroll={this.props.sensitivePageScroll}
onPageScrollStateChanged={this.props.onPageScrollStateChanged}
onPageScroll={this.props.onPageScroll}
scrollViewStyle={this.props.pageScrollViewStyle}
onSingleTapConfirmed={this.props.onPageSingleTapConfirmed}
onLongPress={this.props.onPageLongPress}
removeClippedSubviews={this.props.removeClippedSubviewsPager}
renderItem={(imageProps, imageDimensions, index) => {
if (!this.props.imagePageComponent) {
return <Image {...imageProps} />;
} else {
return this.props.imagePageComponent(imageProps, imageDimensions, index);
}
}}
onPageSelected={(index) => {
this.props.onChangePhoto(images[index].id, index);
this.props.onPageSelected &&
this.props.onPageSelected(index);
}}
onDoubleTapConfirmed={this.props.onDoubleTapConfirmed}
onDoubleTapStartReached={this.props.onDoubleTapStartReached}
onDoubleTapEndReached={this.props.onDoubleTapEndReached}
onPinchTransforming={this.props.onPinchTransforming}
onPinchStartReached={this.props.onPinchStartReached}
onPinchEndReached={this.props.onPinchEndReached}
enableScale={this.props.enableScale}
enableTranslate={this.props.enableTranslate}
resizeMode={this.props.resizeMode}
enableResistance={this.props.enableResistance}
resistantStrHorizontal={this.props.resistantStrHorizontal}
resistantStrVertical={this.props.resistantStrVertical}
onViewTransformed={this.props.onViewTransformed}
onTransformGestureReleased={(transform, i) => {
if (this.props.enableVerticalExit) {
this._handleVerticalSwipe(transform);
}
if (this.props.onTransformGestureReleased) {
this.props.onTransformGestureReleased(transform, i);
}
}}
onSwipeUpReleased={(transform, i) => {
this.props.onSwipeUpReleased &&
this.props.onSwipeUpReleased(transform, i);
}}
onSwipeDownReleased={(transform, i) => {
this.props.onSwipeDownReleased &&
this.props.onSwipeDownReleased(transform, i);
}}
maxScale={this.props.maxScale}
maxOverScrollDistance={this.props.maxOverScrollDistance}
onEndReached={this.props.onEndReached}
onEndReachedThreshold={this.props.onEndReachedThreshold}
/>
{
renderPageFooter &&
<PageFooter
renderPageFooter={renderPageFooter}
image={imageSource}
galleryIndex={imageSource.index}
onClose={onClose}
/>
}
</View>
);
}
render() {
const {
width,
height
} = this.state;
const imageSource = this.props.images[this.props.galleryIndex];
if (Platform.OS === "ios") {
return this._renderIOSVerticalScrollView(
width,
height,
imageSource
);
}
return (
this._renderAndroidVerticalView(
width,
height,
imageSource
)
);
}
}