Why my ScrollView hide my image in React Native? - javascript

I want to add a scrollView in my screen after text and image.
return (
<View>
<Text>Name</Text>
<Image source = {{uri : 'myUri' }} style = {styles.image}/>
<ScrollView>
<View>
<Text>City</Text>
<Text>Tokyo</Text>
</View>
<View>
<Text>Language</Text>
<Text>Japanese</Text>
</View>
</ScrollView>
</View>
);
Here is the style of my image:
image: {
flex: 1,
width: null,
height: null,
resizeMode: 'contain',
marginTop: 3,
marginBottom: 3,
},
The image never shows up with the scrollView.

Did you specify a length for your ScrollView?
Because you make the image's width and height null, the image tries to fill the empty spaces of the page. If you don't give your ScrollView a specific height, it wil fill the screen, so your image cannot find an empty space for itself.
You may need to change the height of the image with a specific value, or you can combine your text and image in a different view and give that view a specific height.
<View style = {styles.customStyle}> // change your style here
<Text>Name</Text>
<Image source = {{uri : 'myUri' }} style = {styles.image}/>
</View>

Related

react native ImageBackground not using full width

I have a Screen:
return (
<SafeAreaView style={styles.container}>
<ImageBackground source={require('../../../../assets/start.png')} resizeMode="cover" style={styles.image}>
<Text>Some Text</Text>
</ImageBackground>
</SafeAreaView>
);
And these are the styles I'm using:
const styles = StyleSheet.create({
container: {
flex: 1,
backgroundColor: 'white',
},
image: {
flex: 1,
justifyContent: 'center',
},
})
The problem is my background Image has white space around it.
From the above image you can see that the image has a gap at the top and the left side, it also has the same gap on the bottom and right.
Im trying to get this image edge to edge. Any idea?
iv tried adding 100% width and height and applying resize properties to the image, but its not working?

Images in FlatList not displayed

I am using react native and firebase to create an application that's somewhat similar to a social network. In the profile screen I am trying to display the images that the user posted in a FlatList that has 3 columns. My problem is, when trying to display the images so that they occupy the full width of the FlatList, they don't seem to get displayed. However, when I set a fixed height, they do. I would like to make it so that they are shown with a 1/1 aspect ratio without having to fix a height.
This is my code:
<View style={styles.galleryContainer}>
<FlatList
numColumns={3}
horizontal={false}
data={posts}
renderItem={({ item }) => (
<View style={styles.imageContainer}>
<Image
style={styles.image}
source={{ uri: item.downloadURL }}
/>
</View>
)}
/>
</View>
And the styles:
galleryContainer: {
flex: 1
},
image: {
flex: 1,
aspectRatio: 1/1,
height: 120
},
imageContainer: {
flex: 1 / 3
}
I have tried setting the height to 100% and that did not work either, any ideas on what might be causing this?
Edit: I solved it by using useWindowDimensions and fetching the window size and dividing it by 3. This is the codethat I used to set the style:
const imageWidth = Math.floor(useWindowDimensions().width/3);
style={{width:imageWidth, aspectRatio:1/1, flex:1, height:imageWidth}}

React Native: trucate text if bigger than width percentage

in react native having a Text component with a given width in percentages how can I trucate that text with ellipsis if the resulting text is bigger than the given width?
<Text style={{width:'50%'}}>{ dynamic.text }</Text>
Thanks in advance.
You can pass numberOfLines prop.
This is used to truncate the text. You can use this prop with another prop called ellipsizeMode to define how text will be truncated.
Use the property numberOfLines, that can be passed to the <Text> and then just update the styling.
<View style={styles.container}>
<Text numberOfLines={1} style={styles.text}>{dynamic.text}</Text>
</View>
var styles = StyleSheet.create({
container: {
flexDirection: 'row',
padding: 10
},
text: {
flex: 1,
width: '50%'
}
});

Overlay button on top of Image in React Native

I'm trying to achieve the following effect in React Native:
The image has a button in the corner. The button is always within the corner of the image regardless of the image's size or aspect ratio, and no part of the image is clipped (it is always scaled down to fit fully within a box).
The trouble I'm having in React Native is that the Image component's size doesn't always match the scaled-down size of the image. If I fix the image's height to 300, set flex 1 to make the image's width expand to fill its contents, and the image is a portrait, the Image component with being the full width of the container, but the image within the component will have a width of much less. Therefore, the typical approach for having a view overlay another view doesn't work as I would like it to- my overlay also covers the padding around the image, and the button (anchored to the corner) appears outside of the image.
Here's what it looks like in React Native:
The X is a placeholder for the button. It is set to anchor to the top-left of a View that's a child of the same View that the Image is a child of. The backgroundColor of the image is set to green to demonstrate how the width of the Image component is different from the width of the picture that's inside the component.
The goal is that the X would be inside of the image regardless of its aspect ratio. I think I could do something based on grabbing the image's dimension and scaling the height and width of the Image component, but that sounds complicated and fragile. Is this possible in a responsive way with styling?
Demonstration code:
<View
style={{
marginLeft: 7,
marginRight: 7,
backgroundColor: 'blue',
}}
>
<View
style={{
height: 300,
flex: 1,
}}
>
<Image
source={imageSource}
style={{
flex: 1,
height: undefined,
width: undefined,
backgroundColor: 'green',
}}
resizeMode="contain"
/>
</View>
<View
style={{
position: 'absolute',
right: 5,
top: 5,
backgroundColor: 'transparent',
}}
>
<Text style={{ color: 'white' }}>X</Text>
</View>
</View>
From React-native v0.50.0 <Image> with nested content is no longer supported. Use <ImageBackground> instead.
<ImageBackground
source={imageSource}
>
<View>
<Text>×</Text>
</View>
</ImageBackground>
Here is how I accomplished that:
import React, { Component } from "react";
import { View, Image, StyleSheet } from "react-native";
import { Ionicons } from "#expo/vector-icons";
class MyCard extends Component {
render() {
return (
<View style={styles.container}>
<Image
resizeMode="cover"
style={styles.cover}
source={{ uri: "https://picsum.photos/700" }}
/>
<Ionicons style={styles.close} name="ios-close-circle" size={25} />
</View>
);
}
}
export default MyCard;
const styles = StyleSheet.create({
container: {
margin: 5,
width: 160,
height: 200
},
cover: {
flex: 1,
borderRadius: 5
},
close: {
margin: 5,
position: "absolute",
top: 0,
left: 0,
width: 25,
height: 25,
color: "tomato"
}
});
Here is how it looks like :
Updated 29 Jun 2019
Now(react-native#0.60-RC) there's a specific component to wrap elements as image background, ImageBackground. Go for the official documentation.
Following Gist has been changed.
Original Answer
We can use <Image/> display images, and we can use it as a background-image hack.
try this
<Image
source={imageSource}
>
<View>
<Text>×</Text>
</View>
</Image>
this gist is a full demo for your need.
or you can see it live at expo:
<div data-snack-id="B1SsJ7m2b" data-snack-platform="ios" data-snack-preview="true" data-snack-theme="light" style="overflow:hidden;background:#fafafa;border:1px solid rgba(0,0,0,.16);border-radius:4px;height:505px;width:100%"></div>
<script async src="https://snack.expo.io/embed.js"></script>
So the way you do this, as #ObooChin mentioned, is to use Image.getSize() to get the actual size of the image, then generate a height and width based on a) the maximum space you want the image to take up, and b) the aspect ratio of the actual image's dimensions.
import React, { Component } from 'react';
import {
StyleSheet,
Image,
View,
Dimensions,
} from 'react-native';
export default class FlexibleThumbnail extends Component {
constructor(props) {
super(props)
this.state = {
imageWidth: 0,
imageHeight: 0,
source: null,
}
}
componentWillMount() {
this._updateState(this.props)
}
componentWillReceiveProps(nextProps) {
this._updateState(nextProps)
}
_updateState(props) {
const {source} = props;
const height = props.maxHeight;
const width = props.maxWidth || Dimensions.get('window').width;
const imageUri = source.uri;
Image.getSize(imageUri, (iw, ih) => {
const {imageWidth, imageHeight} = /* some function that takes max height, width and image height, width and outputs actual dimensions image should be */
this.setState({
imageWidth,
imageHeight,
source,
});
});
}
render() {
const {source, height, width, imageWidth, imageHeight} = this.state;
const overlay = (/* JSX for your overlay here */);
// only display once the source is set in response to getSize() finishing
if (source) {
return (
<View style={{width: imageWidth, height: imageHeight}} >
<Image
style={[ imageStyle, {width: imageWidth, height: imageHeight} ]}
resizeMode="contain"
source={source}
/>
<View style={{
position: 'absolute',
top: 0,
bottom: 0,
left: 0,
right: 0,
backgroundColor: 'transparent',
}}>
{overlay}
</View>
</View>
);
}
return (
<View />
)
}
}
The attempt is still a bit rough, but I'm working on turning this into a library where you can specify max height, width, and the overlay you want to use, and it handles the rest: https://github.com/nudgeyourself/react-native-flexible-thumbnail.

2 Different Background Colours For ScrollView bounce

I have a ScrollView that has a top section with one background colour and a bottom section with another different colour.
When a user scrolls past the content and the view bounces (elastic over-extend), how could I make it so the background is consistent with either the top or the bottom, depending on the scroll direction?
I wouldn't play with the contentInset and contentOffset of the ScrollView as if your content changes, it might change the position of your scrollview.
You can do something very simple by just adding a View at the very top of your ScrollView:
// const spacerHeight = 1000;
<ScrollView>
{Platform.OS === 'ios' && (
<View
style={{
backgroundColor: 'red',
height: spacerHeight,
position: 'absolute',
top: -spacerHeight,
left: 0,
right: 0,
}}
/>
)}
</ScrollView>
On iOS, you can render a spacer View on top of the ScrollView, and use contentInset to render it "off-screen", contentOffset to set the initial scroll position to offset the inset:
render() {
const isIos = Platform.OS === 'ios'
const SPACER_SIZE = 1000; //arbitrary size
const TOP_COLOR = 'white';
const BOTTOM_COLOR = 'papayawhip';
return (
<ScrollView
style={{backgroundColor: isIos ? BOTTOM_COLOR : TOP_COLOR }}
contentContainerStyle={{backgroundColor: TOP_COLOR}}
contentInset={{top: -SPACER_SIZE}}
contentOffset={{y: SPACER_SIZE}}>
{isIos && <View style={{height: SPACER_SIZE}} />}
//...your content here
</ScrollView>
);
}
Because contentInset and contentOffset are iOS only, this example is conditioned to degrade gracefully on Android.
The accepted solution did not work well for me because I need to put flexGrow: 1 on the contentContainerStyle. Using insets/offsets didn't make the content grow the way I want, otherwise it worked not so bad.
I have another solution to suggest: putting a bicolor background layer under a transparent ScrollView, and add colors to your scrollview content. This way, on ios bounce, the bicolor layer under the scrollview will reveal itself.
Here's what I mean by bicolor layer (here the scrollview is empty and transparent)
Now if I put back the ScrollView children (which if a body with blank background, and a footer with yellow background), I get this:
As long as you don't bounce more than 50% of the scrollview height, you will see the appropriate background color.
Here's a component you can use to wrap your scrollview.
const AppScrollViewIOSBounceColorsWrapper = ({
topBounceColor,
bottomBounceColor,
children,
...props
}) => {
return (
<View {...props} style={[{ position: 'relative' }, props.style]}>
{children}
<View
style={{
position: 'absolute',
top: 0,
left: 0,
width: '100%',
height: '100%',
zIndex: -1, // appear under the scrollview
}}
>
<View
style={{ flex: 1, backgroundColor: topBounceColor }}
/>
<View
style={{ flex: 1, backgroundColor: bottomBounceColor }}
/>
</View>
</View>
);
};
And here's how you use it:
<AppScrollViewIOSBounceColorsWrapper
style={{flex: 1}}
topBounceColor="white"
bottomBounceColor="yellowLancey"
>
<ScrollView style={{flex: 1}}>
<WhiteBackgroundBody/>
<YellowBackgroundFooter />
</AppScrollView>
</AppScrollViewIOSBounceColorsWrapper>
Make sure to NOT set a background color to the scrollview, otherwise the bicolor layer will never reveal itself (backgroundColor on contentContainerStyle is fine)
This is, I think the most stupid simple way i found to do it:
<ScrollView style={{backgroundColor: '#000000'}}>
[...]
<View style={{position: "absolute", bottom: -600, left: 0, right: 0, backgroundColor: '#FFFFFF', height: 600}}/>
</ScrollView>
You may adjust the height/bottom absolute value to your likings depending on how far you think the user could scroll.
I personally implemented that into a <ScrollBottom color={"white"}/> component for ease of use in all my ScrollViews
For me, the simplest solution is modification based on Sebastien Lorber answer which doesn't include wrapping, just calling it before (or after) ScrollView component:
Create component:
interface IScrollViewBackgroundLayer {
topBounceColor: string;
bottomBounceColor: string;
}
export const ScrollViewBackgroundLayer = ({
topBounceColor,
bottomBounceColor,
}: IScrollViewBackgroundLayer): ReactElement => (
<View
style={{
position: 'absolute',
top: 0,
left: 0,
width: '100%',
height: '100%',
zIndex: -1, // appear under the scrollview
}}>
<View style={{ flex: 1, backgroundColor: topBounceColor }} />
<View style={{ flex: 1, backgroundColor: bottomBounceColor }} />
</View>
);
and use it like this:
return (
<SafeAreaView style={styles.container}>
<ScrollViewBackgroundLayer topBounceColor={topBounceColor} bottomBounceColor={bottomBounceColor} />
<ScrollView>
...
</ScrollView>
</SafeAreaView>

Categories