react-native-fast-image icon indicating copy to clipboard operation
react-native-fast-image copied to clipboard

Stateful changes in "resizeMode" prop on Android do not affect the image

Open oakleyaidan21 opened this issue 3 years ago • 5 comments

Describe the bug When you change the resizeMode prop depending on the state, like in the example below, the image does not change to the new resizeMode on Android. It works fine on iOS.

To Reproduce Here's a small example:

const App: React.FC = () => {
  const [resizeMode, setResizeMode] = useState(FastImage.resizeMode.contain);

  return (
    <View style={{flex: 1, justifyContent: 'center', alignItems: 'center'}}>
      <FastImage
        style={{width: 300, height: 700, backgroundColor: 'blue'}}
        source={{
          uri:
            'https://bloximages.newyork1.vip.townnews.com/chronicleonline.com/content/tncms/assets/v3/editorial/8/10/8104fdd4-c181-11ea-85cc-7721a478bede/5f066f66c0e74.image.jpg',
        }}
        resizeMode={resizeMode}
      />
      <TouchableOpacity
        onPress={() =>
          setResizeMode(
            resizeMode == FastImage.resizeMode.stretch
              ? FastImage.resizeMode.contain
              : FastImage.resizeMode.stretch,
          )
        }>
        <Text>Current mode: {resizeMode}</Text>
      </TouchableOpacity>
    </View>
  );
};

Expected behavior I expected the image to change to the current resizeMode prop given, as it does in the default react-native Image component.

Screenshots N/A

Dependency versions

  • React Native version: 0.63.4
  • React version: 16.31.1
  • React Native Fast Image version: 8.3.4

oakleyaidan21 avatar Jan 18 '21 04:01 oakleyaidan21

hi @oakleyaidan21 , any alternative you got for this?

Dhanraj-Naik avatar May 08 '21 08:05 Dhanraj-Naik

@Dhanraj-Naik sadly no, I ended up just using the regular react native Image instead for images I needed to resize on the fly.

oakleyaidan21 avatar May 13 '21 00:05 oakleyaidan21

Hello,

I encountered the same issue on Android with the following code:

    const resizeMode = useMemo(() => {
           return isInLandscapeMode ? FastImage.resizeMode.cover : FastImage.resizeMode.contain
       }, [isInLandscapeMode])

    return (
            <Image
                height={theme.device.screenWidth * ratio}
                resizeMode={resizeMode}
                src={src}
                style={{
                    width: '100%',
                    height: '100%',
                }}
                width={theme.device.screenWidth}
            />

I ended up using the same workaround as @oakleyaidan21 (using native image).

Kevinnko avatar Nov 09 '21 15:11 Kevinnko

Hi there!

I've encountered this bug too. I found a simple solution you can use to make RNFI pick up your resizeMode property. It seems that the library doesn't re-apply the resizeMode property after values change.

I've used a build in React Native Image.getSize property to calculate the aspect ratio for the image during the render in the useEffect hook. First, we will receive width & height and based on these values, and we can calculate the ratio. As soon as we get the ratio, you can render the RNFI component with the ternary resizeMode property.

It might not work for all cases, but it will work if you load the network images.

Here is a snippet:

import { Image } from 'react-native'

  // your component
  const [aspectRatio, setAspectRatio] = useState(null)
  useEffect(() => {
    Image.getSize(uri,
      (width, height) => {
        setAspectRatio(width / height)
      },
      error => {
        console.error(`Couldn't get the image size: ${error.message}`)
      }
    )
  }, [])

   const resizeMode = isHorizontal ? 'cover' : 'contain'
   const aspectRatioCalculated = aspectRatio !== null
  
   return (
    {aspectRatioCalculated && (
      <FastImage
        ...
        resizeMode={resizeMode}
      />
     )}
  )

blackPeanut avatar Feb 08 '22 23:02 blackPeanut

Since a change of resizeMode doesn't have any effect on Android one (blunt) solution is to trigger re-render of the component. This can be achieved by simply changing the key of a component.

Simple example:

const MyImage = () => {
    const resizeMode = someBoolean ? 'cover' : 'contain'

    const additionalProps = Platform.OS === 'android' ? { key: resizeMode } : {}

    return (
        <FastImage
            ...
            {...additionalProps}
            resizeMode={resizeMode}
        />
    )
}

jensneuber avatar Aug 03 '22 12:08 jensneuber