Search code examples
react-nativereact-native-gesture-handler

Float an image zooming on an "instagram-like" news feed in react-native


I'm working on an "instagram-like" news feed for an existing react native (0.63.4) application. At this stage I'm using the react-native-gesture-handler (1.10) to handle the pinch/zoom functionality using its PinchGestureHandler and FlatList implementations.

I have an outer vertical flatlist for scrolling the new items and, for each item, an inner horizontal flat list to scroll the images left and right.

If I scale the image inline then it works fine, though it's a little slow due to having to re-layout all the other items.

What I'd like to do is "float" the image above everything else and then snap back after zooming. I can do all of that, except floating the image. I've tried setting overflow:'visible' on the entire tree, but it doesn't help zIndex and elevation also don't seem to help.

Visually I'd like to (kind of) pop the image out while zooming, then it can snap back at the end. How do I do this?

--Implementation details: The feed is just an array of NewsItem:

interface NewsItem {
    id: string,
    title: string,
    images: NewsImage[],
    datePublished: Date
}
interface NewsImage {
    id: string,
    uri: string,
    width: number,
    height: number,
    ref: RefObject<PinchGestureHandler>
}

imageRefs is a flattened list of references for all the images.

The main layout is like this (slightly simplified):

<View>
    <FlatList 
        waitFor={imageRefs}
        data={newsFeed}
        keyExtractor={item => item.id}
        renderItem={({item}) => <NewsItem item={item} /> } />
</View>    

NewsItem

<View>
    <Text>{props.item.title}</Text>
    <FlatList
        horizontal={true} 
        waitFor={props.item.images.map(img => img.ref)}
        data={props.item.images}
        keyExtractor={img => img.id}
        renderItem={({item})} => <NewsImage info={item} />
    />
</View>

NewsImage has all the code to handle the pinch/zoom transform stored in the variables:

  • scale
  • scaledWidth
  • scaledHeight
  • xScaledTranslate
  • yScaledTranslate With the layout:
<View style={{
                width: info.width * minScale, 
                height: info.height * minScale, 
                position: 'relative',
            }}>
    <Animated.View style={{
            position:'absolute', 
            overflow:'visible',
            width:scaledWidth,
            height:scaledHeight,
    }}>
        <PinchGestureHandler 
            onGestureEvent={pinchGestureEventHandler}
            onHandlerStateChange={pinchStateEventHandler}
            ref={ref}
            >
            <Animated.Image
                defaultSource={require('../Shared/assets/logos/bootsplash_logo.png')}
                source={info}
                style={{
                        width: info.width,
                        height: info.height,
                        overflow:"visible",
                        transform: [
                            {translateX: xScaledTranslate},
                            {translateY: YScaledTranslate},
                            {scale: scale},
                        ]
                    }} 
                resizeMode='cover'
                />
        </PinchGestureHandler>
    </Animated.View>
</View>


Solution

  • I dunno did you solved this issue, but simply you can't do that with FlatList. I had the similar issue and solved it to converting my FlatList to a ScrollView