在我的React Native应用程序中,我从具有未知维度的API中提取图像。如果我知道所需的宽度,如何自动缩放高度?
示例:
我将宽度设置为Dimensions.get('window').width
。如何设置高度并保持相同的比例?
export default class MyComponent extends Component {
constructor(props) {
super(props)
this.state = {
imgUrl: 'http://someimg.com/coolstuff.jpg'
}
}
componentDidMount() {
// sets the image url to state
this.props.getImageFromAPi()
}
render() {
return (
<View>
<Image
source={uri: this.state.imgUrl}
style={styles.myImg}
/>
<Text>Some description</Text>
</View>
)
}
}
const styles = StyleSheet.create(
myImg: {
width: Dimensions.get('window').width,
height: >>>???what goes here???<<<
}
)
答案 0 :(得分:32)
试试这个:
import React, { Component, PropTypes } from "react";
import { Image } from "react-native";
export default class ScaledImage extends Component {
constructor(props) {
super(props);
this.state = { source: { uri: this.props.uri } };
}
componentWillMount() {
Image.getSize(this.props.uri, (width, height) => {
if (this.props.width && !this.props.height) {
this.setState({
width: this.props.width,
height: height * (this.props.width / width)
});
} else if (!this.props.width && this.props.height) {
this.setState({
width: width * (this.props.height / height),
height: this.props.height
});
} else {
this.setState({ width: width, height: height });
}
});
}
render() {
return (
<Image
source={this.state.source}
style={{ height: this.state.height, width: this.state.width }}
/>
);
}
}
ScaledImage.propTypes = {
uri: PropTypes.string.isRequired,
width: PropTypes.number,
height: PropTypes.number
};
我将网址作为名为uri
的道具传递。您可以将width
道具指定为Dimensions.get('window').width
,这应该涵盖它。
请注意,如果您知道要将高度设置为什么,并且需要调整宽度以保持比率,这也会起作用。在这种情况下,您可以指定height
道具而不是width
道具。
答案 1 :(得分:8)
有一个属性 resizeMode 设置为“包含”
示例:
<Image
source={require('./local_path_to/your_image.png')}
style={{ width: 30 }}
resizeMode="contain"
/>
来源:https://facebook.github.io/react-native/docs/image#resizemode
答案 2 :(得分:3)
看看这个图书馆react-native-scalable-image。它完全符合您的要求。
counter++;
label1.Text = "number " + counter.ToString();
答案 3 :(得分:2)
TypeScript 版本的@TheJizel回答,其中包含style
中的可选failure
属性和Image.getSize
回调:
import * as React from 'react'
import {Image} from 'react-native'
interface Props {
uri: string
width?: number
height?: number
style?
}
interface State {
source: {}
width: number
height: number
}
export default class ScaledImage extends React.Component<Props, State> {
constructor(props) {
super(props)
this.state = {
source: {uri: this.props.uri},
width: 0,
height: 0,
}
}
componentWillMount() {
Image.getSize(this.props.uri, (width, height) => {
if (this.props.width && !this.props.height) {
this.setState({width: this.props.width, height: height * (this.props.width / width)})
} else if (!this.props.width && this.props.height) {
this.setState({width: width * (this.props.height / height), height: this.props.height})
} else {
this.setState({width: width, height: height})
}
}, (error) => {
console.log("ScaledImage:componentWillMount:Image.getSize failed with error: ", error)
})
}
render() {
return <Image source={this.state.source} style={[this.props.style, {height: this.state.height, width: this.state.width}]}/>
}
}
使用示例:
<ScaledImage style={styles.scaledImage} uri={this.props.article.coverImageUrl} width={Dimensions.get('window').width}/>
答案 4 :(得分:2)
@ TheJizel 的挂钩版本。我知道宽度,但想要图像的高度,因此以下内容对我有用:
const ScaledImage = props => {
const [width, setWidth] = useState()
const [height, setHeight] = useState()
const [imageLoading, setImageLoading] = useState(true)
useEffect(() => {
Image.getSize(props.uri, (width1, height1) => {
if (props.width && !props.height) {
setWidth(props.width)
setHeight(height1 * (props.width / width1))
} else if (!props.width && props.height) {
setWidth(width1 * (props.height / height1))
setHeight(props.height)
} else {
setWidth(width1)
setHeight(height1)
}
setImageLoading(false)
}, (error) => {
console.log("ScaledImage,Image.getSize failed with error: ", error)
})
}, [])
return (
height ?
<View style={{ height: height, width: width, borderRadius: 5, backgroundColor: "lightgray" }}>
<Image
source={{ uri: props.uri }}
style={{ height: height, width: width, borderRadius: 5, }}
/>
</View>
: imageLoading ?
<ActivityIndicator size="large" />
: null
);
}
用法:
<ScaledImage width={Dimensions.get('window').width * 0.8} uri={imageurl} />
答案 5 :(得分:1)
首先尝试一下,看看它是否适合您:https://github.com/facebook/react-native/commit/5850165795c54b8d5de7bef9f69f6fe6b1b4763d
如果没有,那么您可以实现自己的图像组件。但是,不是将宽度作为道具,而是覆盖onLayout
方法,该方法为您提供所需的宽度,以便您可以计算高度。如果您不知道宽度并希望RN为您进行布局,则效果会更好。缺点是在布局和渲染一次通过后调用onLayout
。所以你可能会注意到你的组件移动了一点。
答案 6 :(得分:1)
以下是一个非常简单的解决方案的要点,它利用@Haitao Li的建议来使用aspectRatio:
https://gist.github.com/tpraxl/02dc4bfcfa301340d26a0bf2140cd8b9
没有必要的魔法和计算。 Pure&#34; CSS&#34;如果你知道原始图像的尺寸。
答案 7 :(得分:1)
以下代码对我有用:
export default class MyComponent extends Component {
constructor(props) {
super(props)
this.state = {
imgUrl: 'http://someimg.com/coolstuff.jpg'
}
}
componentDidMount() {
// sets the image url to state
this.props.getImageFromAPi()
}
render() {
return (
<View>
<Image
source={uri: this.state.imgUrl}
style={{
width: Dimensions.get('window').width,
height: Dimensions.get('window').width*1.28
}}
/>
<Text>Some description</Text>
</View>
)
}
}
答案 8 :(得分:1)
这个人在世博会上为我工作
<Image style={{flex:1,width:null,height:null }} resizeMode={'contain'} source={{uri: 'http://134.209.40.60/meApunto/1567655610795_1944474896.png'}}></Image>
https://forums.expo.io/t/how-to-fit-a-big-image-into-a-fixed-container-without-resizemode-help/27639
答案 9 :(得分:0)
建议的解决方案有效,但是您必须下载图像两次,一次是确定大小,另一次是实际显示图像,这是另一种方法,图像首先加载平方并调整大小。
import React, { Component, } from "react";
import { Image } from "react-native";
import PropTypes from 'prop-types'
export default class ScaledImage extends Component {
state = {}
componentWillMount() {
const { uri, width, height } = this.props;
this.setState({ source: { uri }, width: width || height, height: height || width });
}
render() {
return (
<Image
source={this.state.source}
onLoad={(value) => {
const { height, width } = value.nativeEvent.source;
if (this.props.width && !this.props.height) {
this.setState({
width: this.props.width,
height: height * (this.props.width / width)
});
} else if (!this.props.width && this.props.height) {
this.setState({
width: width * (this.props.height / height),
height: this.props.height
});
} else {
this.setState({ width: width, height: height });
}
}}
style={{ height: this.state.height, width: this.state.width }}
/>
);
}
}
ScaledImage.propTypes = {
uri: PropTypes.string.isRequired,
width: PropTypes.number,
height: PropTypes.number
};
答案 10 :(得分:0)
基于@TheJizel的想法,我使用AspectRatio样式属性制作了一些东西。设置宽度后,以下类将起作用,但是高度将被省略。这也适用于宽度百分比。
import React from "react";
import { Image } from "react-native";
export default class ScaledImage extends React.Component {
state = {
aspectRatio: 0
}
setAspectRatio(ratio) {
this.setState({
aspectRatio: ratio
});
}
componentWillMount() {
if (Array.isArray(this.props.source)) {
console.warn("ScaledImage received an array as source instead of local file resource or ImageURISource.")
} else if(typeof this.props.source === "number") {
// Resolve local file resource
const resolved = Image.resolveAssetSource(this.props.source);
// We assume 100% width, so we set the aspect ratio we want for it's height
this.setAspectRatio(resolved.width / resolved.height);
} else if (this.props.source.uri) {
// Resolve remote resource
Image.getSize(this.props.source.uri, (width, height) => {
this.setAspectRatio( width / height);
}, (err) => {
console.error(err);
});
} else {
console.warn("ScaledImage did not receive a valid source uri.");
}
}
render() {
if(!this.state.aspectRatio) return null;
const props = {
...this.props,
style: [this.props.style, {
aspectRatio: this.state.aspectRatio
}]
};
return (
<Image {...props} />
)
}
}
用法:
<ScaledImage source={{ uri: "<URI HERE>" }} style={{ width: "100%" }} />
答案 11 :(得分:0)
您有3个数字:
,您应该在宽度样式中放置“屏幕宽度”,并计算 设置样式的高度?? !!
print(get)
和
componentWillMount() {
Image.getSize(this.props.product.image, (width, height) => {
const screenWidth = Math.round(Dimensions.get('window').width);
this.setState({screenWidth:screenWidth});
Calculatedheight = screenWidth * height / width ;
this.setState({Calculatedheight : Calculatedheight });
});
}
答案 12 :(得分:0)
这是我在生产中使用的一些代码。后端用户可以制作任何大小和宽高比的徽标图像,但是我需要徽标适合最大宽度的确切高度。我的自扩展组件是什么导致的:
import React, { useState, useLayoutEffect, SFC } from "react";
import { Image } from "react-native";
import { Spinner } from "native-base";
interface INetworkImage {
targetHeight: number,
uri: string,
maxWidth: number
}
const NetworkImage: SFC<INetworkImage> = ({ uri, targetHeight, maxWidth }) => {
useLayoutEffect(() => setNaturalDimensions(uri), []);
const [imageWidth, setWidth] = useState(0);
const [imageHeight, setHeight] = useState(0);
const [scaleFactor, setScale] = useState(1);
function setNaturalDimensions(uri: string) {
Image.getSize(uri, (width: number, height: number) => {
if (width > maxWidth) {
// too wide case
setScale(maxWidth / width);
} else {
// scale to height case
setScale(targetHeight / height);
}
setWidth(width);
setHeight(height);
}, (error: any) => {
console.log("error", error);
});
}
function adjustView(e) {
if (e.nativeEvent.layout.width > maxWidth) {
setScale(scaleFactor * (maxWidth/e.nativeEvent.layout.width));
}
}
return (
imageHeight ?
<Image
onLayout={(e) => adjustView(e)}
source={{ uri: uri }}
style={{
width: imageWidth * scaleFactor,
height: imageHeight * scaleFactor,
resizeMode: "contain",
}}
/>:
<Spinner color='#454c7a' />
);
}
export default NetworkImage;
然后我通过将uri,targetHeight和maxwidth用作道具来使用它:
export const deviceWidth = Dimensions.get("window").width;
<NetworkImage
uri={"https://purdyPic.com/image1"}
targetHeight={300}
maxWidth={deviceWidth * 0.85}
/>
答案 13 :(得分:0)
众多解决方案中的一种
<Image source={...} style={{ transform: [{ scale: 0.5 }] }} />
答案 14 :(得分:0)
所以这一切都帮了我很多 ?
我的特定场景涉及从服务器获取纵向或横向图像,我需要将它们放入 <View>
。
这意味着“已知”尺寸是该视图的,我通过 onLayout
获得(简化代码仅显示设置“高度”的示例):
<View onLayout={(event) => setCellHeight(event.nativeEvent.layout.height)}>
现在使用已知的 displayAreaHeight
和 displayAreaWidth
值,我需要调整图像大小:
// Set image size for portrait/landscape scenarios, reducing the total image size when
// an overflow of the display area would occur.
if (image.height > image.width) { // Portrait Image
const ratio = displayAreaHeight / image.height;
imageHeight = displayAreaHeight;
imageWidth = image.width * ratio;
if (imageWidth > displayAreaWidth) {
const heightReductionRatio = displayAreaWidth / imageWidth;
imageHeight *= heightReductionRatio;
imageWidth = displayAreaWidth;
}
} else {
const ratio = displayAreaWidth / image.width;
imageHeight = image.height * ratio;
imageWidth = displayAreaWidth;
if (imageHeight > displayAreaHeight) {
const widthReductionRatio = displayAreaHeight / imageHeight;
imageWidth *= widthReductionRatio;
imageHeight = displayAreaHeight;
}
}
希望这个,连同这里的所有其他伟大的反应,帮助别人?
答案 15 :(得分:0)
基于以上答案,我制作了以下功能组件:
import { useFocusEffect } from '@react-navigation/native';
import React from 'react';
import { ImageProps, ImageURISource } from 'react-native';
import { useIsMounted } from '../../hooks/is-mounted';
import { DrImageStyl } from './styled';
import { getImageSizes } from '../../utils/util';
interface DrSource extends ImageURISource {
uri: string;
}
interface DrImageProps extends ImageProps {
source: DrSource;
width?: number;
height?: number;
}
const DrImage: React.FC<DrImageProps> = ({
width: widthProp,
height: heightProp,
source,
...rest
}: DrImageProps) => {
const isMountedRef = useIsMounted();
const [sizes, setSizes] = React.useState({
width: widthProp,
height: heightProp,
});
useFocusEffect(
React.useCallback(() => {
const getImageSizesState = async () => {
try {
const { width, height } = await getImageSizes({
uri: source.uri,
width: widthProp,
height: heightProp,
});
if (isMountedRef.current) {
setSizes({ width, height });
}
} catch (error) {
console.log('Erro em dr-image getImageSizesState:', error);
}
};
getImageSizesState();
}, [widthProp, heightProp, source.uri])
);
return (
<>
{!!sizes.height && !!sizes.width && (
<DrImageStyl sizes={sizes} source={source} {...rest} />
)}
</>
);
};
export default DrImage;
useIsMounted:
import React from 'react';
export const useIsMounted = (): React.MutableRefObject<boolean> => {
const isMountedRef = React.useRef(false);
React.useEffect(() => {
isMountedRef.current = true;
return () => {
isMountedRef.current = false;
};
}, []);
return isMountedRef;
};
DrImageStyl:
import React from 'react';
import styled, { css } from 'styled-components/native';
interface Sizes {
width?: number;
height?: number;
}
interface DrImageStylProps {
sizes: Sizes;
}
export const DrImageStyl = styled.Image<DrImageStylProps>`
${({ sizes }) => {
const { width, height } = sizes;
return css`
${width ? `width: ${width}px;` : ''}
${height ? `height: ${height}px;` : ''}
`;
}}
`;
getImageSizes:
import { Image } from 'react-native';
interface GetImageSizesParams {
uri: string;
height?: number;
width?: number;
}
export function getImageSizes({
height: heightParam,
width: widthParam,
uri,
}: GetImageSizesParams): Promise<{
width: number;
height: number;
}> {
return new Promise((resolve, reject) => {
function onSuccess(width: number, height: number) {
let widthResolve: number | undefined;
let heightResolve: number | undefined;
if (widthParam && !heightParam) {
widthResolve = widthParam;
heightResolve = height * (widthParam / width);
} else if (!widthParam && heightParam) {
widthResolve = width * (heightParam / height);
heightResolve = heightParam;
} else {
widthResolve = widthParam;
heightResolve = heightParam;
}
resolve({
width: widthResolve as number,
height: heightResolve as number,
});
}
function onError(error: any) {
reject(error);
}
try {
Image.getSize(uri, onSuccess, onError);
} catch (error) {
console.log('error', error);
}
});
}