最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

javascript - Scale image down to device width in React Native ScrollView - Stack Overflow

programmeradmin2浏览0评论

I have an image I'd like to be full width of the device screen.

Using just a View I can achieve this:

<View style={{flex:1}}>
     <Image resizeMode="contain" style={{flex: 1, height: undefined, width: undefined}} source={this.props.images.infoImage} />
</View>

Changing this to a ScrollView causes the image to stop rendering pletely:

<ScrollView style={{flex:1}}>
     <Image resizeMode="contain" style={{flex: 1, height: undefined, width: undefined}} source={this.props.images.infoImage} />
</ScrollView>

I found that if I set a height on the image it would render...but I want the image to dynamically respond to the size of the device.

How can I solve this without declaring an explicit height?

I have an image I'd like to be full width of the device screen.

Using just a View I can achieve this:

<View style={{flex:1}}>
     <Image resizeMode="contain" style={{flex: 1, height: undefined, width: undefined}} source={this.props.images.infoImage} />
</View>

Changing this to a ScrollView causes the image to stop rendering pletely:

<ScrollView style={{flex:1}}>
     <Image resizeMode="contain" style={{flex: 1, height: undefined, width: undefined}} source={this.props.images.infoImage} />
</ScrollView>

I found that if I set a height on the image it would render...but I want the image to dynamically respond to the size of the device.

How can I solve this without declaring an explicit height?

Share Improve this question asked Mar 1, 2017 at 15:33 callmetwancallmetwan 1,3502 gold badges14 silver badges32 bronze badges 2
  • See my answer to this question: stackoverflow./questions/42170127/… – TheJizel Commented Mar 1, 2017 at 21:07
  • Have a look at react-native-scalable-image – Ihor Burlachenko Commented Jan 17, 2018 at 12:57
Add a ment  | 

3 Answers 3

Reset to default 6

As per @martinarroyo's ment I added contentContainerStyle={{flex:1}} to the ScrollView, like so:

<ScrollView contentContainerStyle={{flex:1}}>
    <Image resizeMode="contain" style={{flex: 1, width: undefined, height: undefined}} source={this.props.images.infoImage} />
</ScrollView

This pletely resolved my issue. The image is the full width of the display while maintaining the correct aspect ratio.

EDIT: Turns out the image frame height stays the same but the image scales down. This means it has large chunks of padding on the top and bottom. As of now I don't know how to remove it.

EDIT 2:

It seems there aren't any tools out of the box with RN and ultimately ended up using a modified version of @Ihor Burlachenko's solution. I created a custom ponent that takes desired width/height constraints and scales it based on that. I need to use this for local files, which Image.getSize() method does not work on, so I modified Ihor's solution to allow for that by passing in a dimensions object that contain width and height.

import React from 'react';
import { Image } from 'react-native';

export default class ScalableImage extends React.Component {
    constructor(props) {
        super(props);

        this.state = {
            width: null,
            height: null,
        }
    }

    ponentDidMount() {
        if(typeof this.props.source === 'string') {
            Image.getSize(this.props.source, this._calculateImageDimensions, console.log);
        } else if(this.props.dimensions) {
            this._calculateImageDimensions(this.props.dimensions.width, this.props.dimensions.height)
        }
    }

    render() {
        return (
            <Image
                { ...this.props }
                style={[
                    this.props.style,
                    { width: this.state.width, height: this.state.height }
                ]}
            />
        );
    }

    _calculateImageDimensions(width, height) {
        let ratio;

        if (this.props.width && this.props.height) {
            ratio = Math.min(this.props.width / width, this.props.height / height);
        }
        else if (this.props.width) {
            ratio = this.props.width / width;
        }
        else if (this.props.height) {
            ratio = this.props.height / height;
        }

        this.setState({ width: width * ratio, height: height * ratio });
    }
}

ScalableImage.propTypes = {
    width: React.PropTypes.number,
    height: React.PropTypes.number,
    dimensions: React.PropTypes.object
};

I then use it as so:

<ScalableImage source={require('../path/to/local/image.png')} 
               width={Dimensions.get('window').width()} 
               dimensions={{width: 700, height: 400}} />

As a last resource, you can use Dimensions.

Get the windows's width and height on every render, that way you'll account for changes in size (basically, rotations) and will match every device.

You can use it like this:

import {Dimensions} from 'react-native'+
// Then, in your ponent:
render(){
    const {width, height} = Dimensions.get('window'):
    return (<ScrollView style={{flex:1}}>
     <Image resizeMode="contain" style={{flex: 1, height, width}} source={this.props.images.infoImage} />
</ScrollView>)
}

I ended up wrapping React Image inside custom Image ponent which calculates height dynamically to keep the image ratio in onComponentDidMount:

Image.getSize(this.props.source.uri, (width, height) => {
    let ratio;

    if (this.props.width && this.props.height) {
        ratio = Math.min(this.props.width / width, this.props.height / height);
    }
    else if (this.props.width) {
        ratio = this.props.width / width;
    }
    else if (this.props.height) {
        ratio = this.props.height / height;
    }

    this.setState({ width: width * ratio, height: height * ratio });
}, console.log);

And then I use it like that:

<Image width={Dimensions.get('window').width} source={{uri: '<image uri>'}} />
发布评论

评论列表(0)

  1. 暂无评论