Skip to content

Instantly share code, notes, and snippets.

@DeVoresyah
Created February 17, 2021 09:42
Show Gist options
  • Save DeVoresyah/94693328df7775cacf3385217697fa23 to your computer and use it in GitHub Desktop.
Save DeVoresyah/94693328df7775cacf3385217697fa23 to your computer and use it in GitHub Desktop.
React Native Multi Image + Viewer
import React, { useState, memo, useImperativeHandle, forwardRef } from 'react'
import PropTypes from 'prop-types'
import { Modal, View, Text } from 'react-native'
import ViewPager from '@react-native-community/viewpager'
import { BlurView } from '@react-native-community/blur'
import Icon from 'react-native-vector-icons/FontAwesome5'
// Components
import Image from '../App/Image'
import Button from '../Button/Button'
// Styles
import styles from '../Styles/Modal/ImageViewerStyle'
import { apply } from '../../Themes/OsmiProvider'
const ImageViewer = forwardRef((props, ref) => {
const { parentRef, data, current, containerStyle } = props
const [modalShow, setModalShow] = useState(false)
const [currentPage, setCurrentPage] = useState(current)
useImperativeHandle(ref, () => ({
showModal() {
setModalShow(true)
}
}))
const _renderClose = () => {
return (
<View style={styles.closeContainer}>
<Button style={styles.btnClose} onPress={() => setModalShow(false)} rippleRadius={15}>
<Icon name='times' size={25} color={apply('white')} />
</Button>
</View>
)
}
const _renderFooterCount = () => {
return data?.length !== 0 ? (
<View style={styles.footerContainer}>
<View style={styles.footerCountContainer}>
<Text style={styles.footerCountLabel}>{currentPage + 1}/{data?.length}</Text>
</View>
</View>
) : null
}
const onPageSelected = (e) => {
setCurrentPage(e?.nativeEvent?.position)
parentRef?.current?.setPage(e?.nativeEvent?.position)
}
return (
<Modal
visible={modalShow}
hardwareAccelerated={true}
transparent={true}
onRequestClose={() => setModalShow(false)}
animationType='fade'
statusBarTranslucent={true}
>
<BlurView
style={styles.blurContainer}
blurType="dark"
blurAmount={5}
reducedTransparencyFallbackColor="black"
/>
<View style={styles.container}>
{_renderClose()}
<ViewPager
orientation='horizontal'
style={[apply('flex bg-transparent'), containerStyle]}
initialPage={currentPage}
onPageSelected={onPageSelected}
transitionStyle="scroll"
>
{data?.map((item, index) => <Image key={index} source={item} style={apply('w/100 bg-transparent rounded-none')} resizeMode='contain' />)}
</ViewPager>
{_renderFooterCount()}
</View>
</Modal>
)
})
// Prop type warnings
ImageViewer.propTypes = {
data: PropTypes.array.isRequired,
initial: PropTypes.number,
onPageScroll: PropTypes.func
}
// Defaults for props
ImageViewer.defaultProps = {
data: [],
initial: 0,
onPageScroll: () => {},
}
export default memo(ImageViewer)
import React, {useRef, useCallback, useState, useMemo, memo, useEffect} from 'react'
import PropTypes from 'prop-types'
import { TouchableOpacity, Animated, View, Text } from 'react-native'
import ViewPager from '@react-native-community/viewpager'
import Images from '../../Images'
// Components
import Image from '../App/Image'
import ImageViewer from '../Modal/ImageViewer'
// Styles
import styles from '../Styles/App/MultiImageStyle'
import { apply } from '../../Themes/OsmiProvider'
const MultiImage = props => {
const { containerStyle, resizeMode, imageStyle, data, initial } = props
const [currentPage, setCurrentPage] = useState(initial ?? 0)
const _modalRef = useRef()
const _sliderRef = useRef()
const onPageSelected = (e) => setCurrentPage(e?.nativeEvent?.position)
const _renderFooterCount = () => {
return data?.length !== 0 ? (
<View style={styles.footerCountContainer}>
<Text style={styles.footerCountLabel}>{currentPage + 1}/{data?.length}</Text>
</View>
) : null
}
const _renderContent = () => {
return data?.length !== 0 ? (
<ViewPager
ref={_sliderRef}
orientation='horizontal'
style={containerStyle}
initialPage={currentPage}
onPageSelected={onPageSelected}
transitionStyle="scroll"
>
{data?.map((item, index) => (
<TouchableOpacity key={index} activeOpacity={1} onPress={() => _modalRef.current.showModal()}>
<Image source={item} style={imageStyle} resizeMode={resizeMode} />
</TouchableOpacity>
))}
</ViewPager>
) : (
<Image source={{ uri: undefined }} style={imageStyle} resizeMode={resizeMode} />
)
}
return (
<View style={apply('flex bg-red-500')}>
<ImageViewer ref={_modalRef} parentRef={_sliderRef} data={data} current={currentPage} onPageSelected={onPageSelected} />
{_renderContent()}
{_renderFooterCount()}
</View>
)
}
// Prop type warnings
MultiImage.propTypes = {
data: PropTypes.array.isRequired,
initial: PropTypes.number,
}
// Defaults for props
MultiImage.defaultProps = {
data: [{
id: 1,
image: Images.dummyCard1
}, {
id: 2,
image: Images.dummyCard2
}, {
id: 3,
image: Images.dummyCard3
}],
initial: 0,
}
export default memo(MultiImage)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment