美文网首页
React-Native图片宽高等比缩放组件(基于Image组件

React-Native图片宽高等比缩放组件(基于Image组件

作者: AizawaSayo | 来源:发表于2021-01-18 16:24 被阅读0次

RN的Image组件必须设置样式的widthheight才能正常显示,但我们通常都不能把高度写死,比如像宽度固定高度自适应的需求。
Image组件有个getSize方法可以帮助我们解决这个问题。(针对通过网络获取的图片)


但这个方法是异步的,每次在副作用中(请求数据)得到了图片数据,再异步处理图片的高度容易产生内存泄露等bug,代码逻辑也显得复杂和冗余。所以单独抽取一个图片组件,直接把图片地址直接传给它,处理宽高这件事就由这个组件来处理。

ScaledImage组件

import React,{ useState, useEffect } from 'react';
import PropTypes from 'prop-types';
import { Image, Dimensions } from 'react-native'
 
const { width: screenWidth, height: screenHeight } = Dimensions.get('window')

const ScaledImage = (props) => {
  const [source, setSource] = useState({uri: props.uri})
  const styles = props.style ? props.style : {} // 定义其他样式
  // 为了区分宽度/高度必要性,width 和 height prop 我们单独传,若有其他样式要求可传给styleProp

  useEffect(() => {
    Image.getSize(props.uri,(width, height) => {
      if (props.width && !props.height) { // 图片宽度固定,高度自适应
        setSource({uri: props.uri, width: props.width, height: height * (props.width / width)});
      } else if (!props.width && props.height) { // 图片高度固定,宽度自适应
        setSource({uri: props.uri, width: width * (props.height / height), height: props.height});
      } else if(!props.width && !props.height){ // 图片宽高都没有传,那就是宽度占满容器,高度自适应
        setSource({uri: props.uri, width: '100%', height: Math.floor(screenWidth/width*height)});
      } else { // 图片宽高都传了
        setSource({uri: props.uri, width: props.width, height: props.height});
      }
    });
  },[])

  const imageStyle = {
    width: source.width, 
    height: source.height, 
    ...styles,
  }
  return <Image source={{uri:source.uri}} style={imageStyle} />
}

ScaledImage.propTypes = {
    uri: PropTypes.string.isRequired, 
    width: PropTypes.number,
    height: PropTypes.number
}

export default ScaledImage

使用组件示例,需要的地方都可以用ScaledImage组件愉快地取代Image

import React, { useEffect, useState, useRef } from 'react'
import ScaledImage from '@components/core/ScaledImage'
import { apiFun } from '@api/fish'

const MuseumDetail = ({ navigation, route }) => {
  const apiUrl = global.baseUrl 
  const [detailInfo, setDetailInfo] = useState(null)
  const { id } = route.params
  const count = useRef(0)

  useEffect(() => {
    const currentCount = count.current;
    const getDetail = async () => {
      const result = await apiFun(id)
      if(count.current !== currentCount) return
      if(result.code === 200){
        let detail = result.data
        // ... 一些其他对数据的处理  
        setDetailInfo(detail)
      }
    }
    getDetail()
    return () => { count.current += 1 }  // 竞态处理
  },[route.params.id])

  return (
    detailInfo && <ScaledImage
    uri={typeof detailInfo.photoSrc === 'string' ? `${apiUrl}${detailInfo.photoSrc}`: apiUrl + detailInfo.photoSrc[0].src}
     width={styles.detailImg.width} 
     style={{borderRadius: 40, marginLeft: 'auto'}}
    /> 
  )
}

export default MuseumDetail

相关文章

网友评论

      本文标题:React-Native图片宽高等比缩放组件(基于Image组件

      本文链接:https://www.haomeiwen.com/subject/jwdxzktx.html