最近在做ReactNative项目,我们的页面有很多图片,发现图片加载效果很卡顿。于是研究了一下RN下图片渐进加载。

原理

首先给图片一个固定宽高的容器,容器中有两个透明度为0的 Image 元素, 其中一个加载缩略图,一个为原图,监听图片加载,调整透明度,给过渡动画。

依赖

react-native-fast-image   用于缓存图片
react-spring/native   用于实现动画效果

对比图

优化前
优化后

核心代码

import React, { FC } from 'react'
import { View, StyleSheet, ImageStyle, ViewStyle, animated } from 'react-native'
import FastImage, { FastImageProps } from 'react-native-fast-image'
import { animated } from 'react-spring/native'
import { useSpring } from 'react-spring'

const AnimatedFastImage = animated(FastImage)

interface ImgStyle extends ImageStyle {
  width: number | string
  height: number | string
}

interface Props extends FastImageProps {
  thumbnailSource?: FastImageProps['source']
  style: ImgStyle
  containerStyle?: ViewStyle
}

export const ProgressiveImage: FC<Props> = ({
  thumbnailSource,
  source,
  style,
  containerStyle,
  ...props
}) => {
  const [thumbOpStyle, setThumbOpStyle] = useSpring(() => ({ opacity: 0, config: { duration: 500 } }))
  const [imgOpStyle, setImgOpStyle] = useSpring(() => ({ opacity: 0, config: { duration: 500 } }))

  function handleThumbnailLoad() {
    setThumbOpStyle({ opacity: 1, config: { duration: 500 } })
  }

  function onImageLoad() {
    setImgOpStyle({ opacity: 1, config: { duration: 500 } })
  }

  return (
    <View style={[styles.container, { width: style.width, height: style.height }, containerStyle]}>
      {thumbnailSource && (
        <AnimatedFastImage
          {...props}
          source={thumbnailSource}
          style={[style, thumbOpStyle]}
          onLoad={handleThumbnailLoad}
          blurRadius={1}
        />
      )}
      <AnimatedFastImage
        {...props}
        source={source}
        style={[styles.imageOverlay, imgOpStyle, style]}
        onLoad={onImageLoad}
      />
    </View>
  )
}

const styles = StyleSheet.create({
  imageOverlay: {
    position: 'absolute',
    left: 0,
    right: 0,
    bottom: 0,
    top: 0,
  },
  container: {
    backgroundColor: '#e1e4e8',
  },
})