React Native: print full image in a Scrollview - react-native

I have an image that is very tall, but not very large. I want to print it in a scrollview, so you can see it all on one screen, but nothing works.
after playing with widths and heights and flexs for my scrollview and my image, the best result I get is when I have on of them with style={{width='100%'}}, like that
<ScrollView style={{width: '100%'}}>
<Image
source={require('./assets/skeleton/fullSkeleton.png')}
resizeMode='cover'
/>
</ScrollView>
which prints the image at full width, but the scrollview's height is the original image's height, which doesn't let me see the whole resized image.
Here, a bad drawing to represent my image, and what I want to see on my phone screen
EDIT:
With this bit of code:
<ScrollView
contentContainerStyle={{alignItems: 'center'}}>
<Image
source={require('./fullSkeleton.png')}
resizeMode='cover'
/>
</ScrollView>
I end up with
Which can be scrolled down to see the rest of the Image. As you can see, it can be navigated vertically, but doesn't take the whole screen's width

This kind of thing in Reat Native is actually quite tricky. But you can do it easily; First get picture dimensions:
const FullWidthPicture = ({ uri }) => {
const [ratio, setRatio] = useState(1);
useEffect(() => {
if (uri) {
Image.getSize(uri, (width, height) => {
setRatio(width / height);
});
}
}, [uri]);
return (
<Image
style={{ width: '100%', height: undefined, aspectRatio: ratio }}
resizeMode="contain"
source={{ uri }}
/>
);
};
And use it like this:
<ScrollView style={{flex: 1}}>
<FulWidthImage uri={pictureUri} />
</ScrollView>

The following may help:
You can use contentContainerStyle to style the contents of the ScrollView. Like this (essentially what you have):
<ScrollView
contentContainerStyle={{alignItems: 'center'}}>
<Image
source={require('./fullSkeleton.png')}
resizeMode='cover'
/>
</ScrollView>
That works for me - I can scroll down the whole image and at the bottom it stays visible.
NB: To make the image cover the whole screen while maintaining the height required, you will need to set the width specifically. In my case on iPhone 7+ that meant adding style={{width: 414}} to the Image component AND changing resizeMode to 'stretch'.
Here is the official take on Image resizing...and getting device dimensions will be useful here too.

Related

Float an image zooming on an "instagram-like" news feed in react-native

I'm working on an "instagram-like" news feed for an existing react native (0.63.4) application. At this stage I'm using the react-native-gesture-handler (1.10) to handle the pinch/zoom functionality using its PinchGestureHandler and FlatList implementations.
I have an outer vertical flatlist for scrolling the new items and, for each item, an inner horizontal flat list to scroll the images left and right.
If I scale the image inline then it works fine, though it's a little slow due to having to re-layout all the other items.
What I'd like to do is "float" the image above everything else and then snap back after zooming. I can do all of that, except floating the image. I've tried setting overflow:'visible' on the entire tree, but it doesn't help zIndex and elevation also don't seem to help.
Visually I'd like to (kind of) pop the image out while zooming, then it can snap back at the end. How do I do this?
--Implementation details:
The feed is just an array of NewsItem:
interface NewsItem {
id: string,
title: string,
images: NewsImage[],
datePublished: Date
}
interface NewsImage {
id: string,
uri: string,
width: number,
height: number,
ref: RefObject<PinchGestureHandler>
}
imageRefs is a flattened list of references for all the images.
The main layout is like this (slightly simplified):
<View>
<FlatList
waitFor={imageRefs}
data={newsFeed}
keyExtractor={item => item.id}
renderItem={({item}) => <NewsItem item={item} /> } />
</View>
NewsItem
<View>
<Text>{props.item.title}</Text>
<FlatList
horizontal={true}
waitFor={props.item.images.map(img => img.ref)}
data={props.item.images}
keyExtractor={img => img.id}
renderItem={({item})} => <NewsImage info={item} />
/>
</View>
NewsImage has all the code to handle the pinch/zoom transform stored in the variables:
scale
scaledWidth
scaledHeight
xScaledTranslate
yScaledTranslate
With the layout:
<View style={{
width: info.width * minScale,
height: info.height * minScale,
position: 'relative',
}}>
<Animated.View style={{
position:'absolute',
overflow:'visible',
width:scaledWidth,
height:scaledHeight,
}}>
<PinchGestureHandler
onGestureEvent={pinchGestureEventHandler}
onHandlerStateChange={pinchStateEventHandler}
ref={ref}
>
<Animated.Image
defaultSource={require('../Shared/assets/logos/bootsplash_logo.png')}
source={info}
style={{
width: info.width,
height: info.height,
overflow:"visible",
transform: [
{translateX: xScaledTranslate},
{translateY: YScaledTranslate},
{scale: scale},
]
}}
resizeMode='cover'
/>
</PinchGestureHandler>
</Animated.View>
</View>
I dunno did you solved this issue, but simply you can't do that with FlatList.
I had the similar issue and solved it to converting my FlatList to a ScrollView
You can use this: https://github.com/postillonmedia/react-native-instagram-zoomable
It's a JS implementation so you can also modify the code as needed. It zooms the view/image/component above everything on the screen. It creates a clone of the element and uses PanGestures to zoom

Get coordinates of touch event relative to Image

I have an image centered on the screen. I need to make it touchable and I need to get the coordinates of the touch event relative to the image. I have wrapped my image in a TouchableOpacity to make it touchable. The problem is that the touch coordinates are relative to the TouchableOpacity and not the Image. The TouchableOpacity is taking up the entire screen but the Image is centered inside it.
I either need to make my TouchableOpacity the same size as the Image, or I need to know the offset of the Image within the TouchableOpacity.
I have tried using OnLayout and the NativeEvent object to get the position of the Image within it's parent but it just returns 0,0.
const {width, height} = Dimensions.get("window");
class Inspection extends React.Component {
handlePress(evt) {
// do stuff
...
}
render() {
return (
<View style={{flex:1, backgroundColor:'#fff'}}>
<TouchableOpacity
onPress={(evt) => this.handlePress(evt)}
style={{backgroundColor: '#3897f0'}}
>
<Image
onLayout={({nativeEvent}) => {
console.log(nativeEvent.layout);
}}
source={require('../../images/wireframe-car.jpg')}
resizeMode='contain'
style={{
maxHeight: height,
maxWidth: width
}}
/>
</TouchableOpacity>
</View>
);
}
}
Console Output:
{height: 683.4285888671875, width: 411.4285583496094, y: 0, x: 0}
I've added a backgroundColor to TouchableOpacity so you can see that it takes up the entire screen.
Is there another way of doing this?
TouchableOpacity would be the same size as of the Image because you haven't given any height to it, you simply need to assign onLayout prop to your TouchableOpacity like this
<View
style={{ flex: 1, backgroundColor: '#fff', alignItems: 'center', justifyContent: 'center' }}>
<TouchableOpacity
onLayout={({ nativeEvent }) => {
console.log(nativeEvent.layout)
}}
style={{}}
onPress={evt => this.handlePress(evt)}>
<Image
source={require('../../images/wireframe-car.jpg')}
resizeMode="contain"
style={{
maxWidth: '100%',
}}
/>
</TouchableOpacity>
</View>
This will give you the exact x and y of Image.
Update
The problem is also with image size, since the image size is quite big so it takes the height of the device and we get x:0 and y:0, in order to resolve this issue we can give the Image component a static height or calculate its height according to width. We can get width and height image from local path like this:
let imageUri = Image.resolveAssetSource(require('../../images/wireframe-car.jpg').uri)
Image.getSize(imageUri , (width, height) => {
console.log(`The image dimensions are ${width}x${height}`);
}, (error) => {
console.error(`Couldn't get the image size: ${error.message}`);
});

Render text with image in React Native

How to render a paragraph with image at right,
the screen design should be similar to the screenshot
React Native does not support text justification in the way you want. You could somewhat emulate this effect for one paragraph at a time by rendering each paragraph in its own Text component, then rendering the following for paragraphs that have accompanying images:
<View style={{flexDirection: 'row'}}>
<Text>Lorem ipsum dolor......</Text>
<Image source={require('./path/to/image.png')} />
</View>
You'll probably want to add some left padding to the image component so the text doesn't run right up against it.
Can you try:
let pic = {
uri: 'https://upload.wikimedia.org/wikipedia/commons/d/de/Bananavarieties.jpg'
};
return(
<View style={styles.container}>
<Image source={pic} style={{width: 360, height: 110}}/>
<Text>React Application Works fine!</Text>
</View>
);

How can I get the image width to fill the card and the height to be flexible?

I'm trying to set the dimensions of the image so that the width will always take up the full width of the card (minus the horizontal margin) and with a flexible height, so that it can scale as it needs to.
How can I do this? It seems that the style needs a height, it won't accept null.
I have tried a LOT of combinations using various resizeModes, heights, widths etc.
Here is the component:
And here is my current code:
renderImage(image) {
const { width, height } = Dimensions.get('window');
if (image) {
return (
<View style={styles.imageContainer}>
<Image
style={{ width, resizeMode: 'contain', height: 300 }}
source={{ uri: image }}
/>
</View>
);
}
}
The aspectRatio property solves this problem nicely.
<Image
style={{ width: '100%', aspectRatio: 1 }}
source={{uri: 'https://online.picture/dynamic_size'}}/>
I had same problem for images from web (where no exact width & height was known) and created react-native-web-image. Currently not for local images, only for remote. Try it, I will be glad if it will help.
Set the width to be the screen width, and set height to be undefined.

Full Screen Background Image behaves differently from network and local storage

I am trying to stretch a background-image to full screen.
Images seem to behave differently when fetched from Network and from Local storage.
This function does not stretch the image as requested (there is a white margin of around 70 pixels from the right):
This is my render() fundtion:
var BackgroundImage = require('./images/logo_og.png');
render(){
return(
<View style={[{flex: 1, alignItems: 'stretch'}]}>
<Image source={BackgroundImage} style={[{flex: 1}]} >
</Image>
</View>
);
The same render function works well displaying the image being fetched from the network:
render(){
return(
<View style={[{flex: 1, alignItems: 'stretch'}]}>
<Image source={{uri:'https://facebook.github.io/react/img/logo_og.png'}} style={[{flex: 1}]} >
</Image>
</View>
);
any idea what is going on?
Similar issue was reported here. Try setting the Image's width to null:
<Image source={BackgroundImage} style={[{flex: 1, width: null}]} >