I just want to know how to display a part of an image in react-native
class InstaClone extends Component {
render() {
return(
<View style={{ flex:1, width:100 + "%", height:100 + "%" }}>
<View style={styles.TopNavStyle}>
<Text style={styles.TopNavTextStyle}>
Instagram
</Text>
</View>
<View style = {styles.userBar}>
<View style = {{ flexDirection:"row" , alignItems:"center" }}>
<Image style = {styles.userPic}
source = {require('../assets/images/photoUser.jpg')}/>
<Text style = {{marginLeft : 10}}>
Mohcouch
</Text>
</View>
<View>
<View style={styles.imageContainer}>
<ImageBackground
source={require('../assets/images/icons.jpg')}
style={styles.image}
></ImageBackground>
</View>
</View>
</View>
<Image
style={{ width:"100%", height:400 }}
source={require('../assets/images/baby.jpg')}
/>
</View>
)
}
}
} , image: {
height: 500,
width: 500,
resizeMode:"cover",
translateX:-80,
translateY: -135,
},
imageContainer: {
height: 40,
backgroundColor:'transparent',
width: 40,
},
})
export default InstaClone
Result :
https://scontent.xx.fbcdn.net/v/t1.15752-0/p280x280/58461695_2231014486986604_1022634010985103360_n.png?_nc_cat=102&_nc_ad=z-m&_nc_cid=0&_nc_zor=9&_nc_ht=scontent.xx&oh=cb81348aae1c524ba9e93d1e02afb120&oe=5D44DF9C
the image of icons :
https://scontent.xx.fbcdn.net/v/t1.15752-0/p280x280/51865955_790216374668323_1242853141917990912_n.jpg?_nc_cat=102&_nc_ad=z-m&_nc_cid=0&_nc_zor=9&_nc_ht=scontent.xx&oh=1c6d18d17e24ec68771be2590fc934c4&oe=5D2CC871
React Native doesn's support a property background-position. It is better to separate the icons in different image files.
But there is a tricky workaround that you can use with your sprite image:
First, you need to round the image pixels in layout size (dp):
const width = PixelRatio.roundToNearestPixel(280);
const height = PixelRatio.roundToNearestPixel(280);
Note: 280 is the size of the image from your post
Then, we need to calculate the same proportion for the size of the icon:
const iconWidth = PixelRatio.roundToNearestPixel(30);
const iconHeight = PixelRatio.roundToNearestPixel(30);
Note: 30 is a random size for our icon, it can be any size.
Now, for the loading of the image, we will use the ImageBackground component from react-native. For imageStyle we will pass the positioning properties of the image:
imageStyle={{
resizeMode: 'cover',
width: width, height: height,
top: -15,
left: -15
}}
Your component should look like this:
<ImageBackground
source={{ uri: image_url }}
style={{ width: iconWidth, height: iconHeight, overflow: 'hidden' }}
imageStyle={{
resizeMode: 'cover',
width: width, height: height,
top: -15,
left: -15
}}
/>
Here is a working demo.
Related
I have a simple page that opens an image with a few styles. However, when I change the height to say... height: SCREEN_HEIGHT - 200, the image gets smaller but does not remain center. Also, it might even be cutting out the image. How can I fix this so I can make the image smaller but remain center?
If I give it a height: 100 and a width: 100, and position it with absolute or justify content, will it look the same across all devices?
Thank you guys for any input at all! I appreciate it more than you know.
import React from'react'
import { StyleSheet, Text, View, Dimensions, Image, Animated} from 'react-native'
const SCREEN_HEIGHT = Dimensions.get('window').height
const SCREEN_WIDTH = Dimensions.get('window').width
const Bars = [
{id : "1", uri: require('./assets/placeholder1.jpg')},
{id : "2", uri: require('./assets/placeholder2.jpg')},
{id : "3", uri: require('./assets/placeholder3.jpg')},
{id : "4", uri: require('./assets/placeholder4.jpg')},
{id : "5", uri: require('./assets/placeholder5.jpg')},
{id : "6", uri: require('./assets/placeholder6.jpg')},
{id : "7", uri: require('./assets/placeholder7.jpg')},
{id : "8", uri: require('./assets/placeholder8.jpg')},
{id : "9", uri: require('./assets/placeholder9.jpg')},
]
export default class App extends React.Component {
render() {
return(
<View style={{flex:1}}>
{/* styles header */}
<View style={{height: 60 }}>
</View>
{/* styles bar images */}
<View style={{flex: 1}}>
<Animated.View style={styles.barImage}>
<Image
style={{flex: 1 ,
height: null,
width: null,
borderRadius: 20
}}
resizeMode='cover'
source={Bars[0].uri} />
</Animated.View>
</View>
{/* styles footer if I even need it */}
<View style={{height: 60 }}>
</View>
</View>
)
}
}
const styles = StyleSheet.create({
barImage: {
height: SCREEN_HEIGHT - 170,
width:SCREEN_WIDTH,
padding: 10,
}
}
)
You are using resizeMode wrong. resizeMode is a prop of the <Image /> component. You have to wrap the <Image /> with a <View /> and give that <View /> a width and height and center that <View />.
<View style={{alignItems: 'center', justifyContent: 'center'}}>
<View style={{width: 100, height: 100}}>
<Image
...
resizeMode='cover'
...
/>
</View>
</View>
In your stylesheet, use the margin elements to center the image. If you set them to auto, it'll center them automatically. You can also use vertical-align and many other center components. Use this website for more context and better understanding with multiple other ways to suit your use case : https://www.w3.org/Style/Examples/007/center.en.html
I have a TextInput that when pressed gets covered by the keyboard. So I wrapped it in a KeyboardAvoidingView. But regardless of the behavior that I set for this view, the TextInput won't move above the keyboard. Using position as the behavior moves the TextInput but only half way above the keyboard, while the other two don't seem to work at all.
I also tried wrapping my entire component with a KeyboardAvoidingView, but doing so breaks the entire layout.
Can anyone help me? I never managed to get KeyboardAvoidingView to work for me and now I really need it. Thanks in advance!
Here is my component. Also worth mentioning is that this component is top level(well, almost top level since it's wrapped in a Router)
const { height, width } = Dimensions.get('screen')
const style = StyleSheet.create({
main: {
height,
width,
flexDirection: 'column',
},
iconSelecter: {
width,
height: 196,
alignItems: 'center',
justifyContent: 'center',
backgroundColor: Colors.primary,
marginTop: 32
},
icon: {
height: 164,
width: 164,
},
saveButton: {
width: 96,
height: 96,
borderRadius: 100,
backgroundColor: Colors.secondary,
alignItems: "center",
justifyContent: "center",
alignSelf: 'center',
position: 'absolute',
bottom: 96 + 32
},
saveIcon: {
height: 54,
width: 54,
},
textInputWrapper: {
borderBottomColor: Colors.textInputBorder,
width: 288,
borderBottomWidth: 1,
alignSelf: 'center',
marginTop: 96,
height: 48,
},
textInput: {
fontWeight: "300",
fontSize: 14,
margin: 0
},
hintWrapper: {
alignSelf: 'center',
marginTop: 4
},
hint: {
fontSize: 12,
fontFamily: "Roboto-Thin",
fontStyle: 'normal',
}
})
const CreateActivity = ({ goBack }: NavigationProps) => {
//////////////////////////////
//State and logic
///////////////
return (
// TODO: Add touchable opacity to dismiss keyboard
<View style={style.main}>
<Appbar title="New activity" canGoBack goBack={goBack} />
<View style={{ flex: 1 }}>
<View style={style.iconSelecter}>
<GestureRecognizer onSwipeLeft={nextIcon} onSwipeRight={lastIcon}>
<Image style={style.icon} source={icons[currentIconIndex]?.file}></Image>
</GestureRecognizer>
</View>
<View style={style.hintWrapper}>
<Text style={style.hint}>Swipe to cycle through the icons</Text>
</View>
<KeyboardAvoidingView>
<View style={style.textInputWrapper}>
<TextInput style={style.textInput} placeholder={"Give this activity a name"} value={name} onChangeText={setName}></TextInput>
</View>
</KeyboardAvoidingView>
<TouchableNativeFeedback onPress={createActivity} background={TouchableNativeFeedback.Ripple("#fff", true)}>
<View style={style.saveButton}>
<Image style={style.saveIcon} source={require("../../assets/icons/light/save.png")}></Image>
</View>
</TouchableNativeFeedback>
</View>
</View>
)
}
export default CreateActivity;
I suggest that you to try wrap all the content of the screen in <KeyboardAvoidingView /> (or make it one of the outermost elements), otherwise it only will slide up its children (the View and the TextInput) leaving the rest of the content in its original position, making the layout look overlaped and weird. If you do that, the value "position" should work fine.
Something like this:
<View style={style.main}>
<Appbar title="New activity" canGoBack goBack={goBack} />
<KeyboardAvoidingView behavior="position" >
<View style={{ flex: 1 }}> // --> Remove flex: 1 if you experience some issue with the positioning
<View style={style.iconSelecter}>
<GestureRecognizer onSwipeLeft={nextIcon} onSwipeRight={lastIcon}>
<Image style={style.icon} source={icons[currentIconIndex]?.file}></Image>
</GestureRecognizer>
</View>
<View style={style.hintWrapper}>
<Text style={style.hint}>Swipe to cycle through the icons</Text>
</View>
<KeyboardAvoidingView>
<View style={style.textInputWrapper}>
<TextInput style={style.textInput} placeholder={"Give this activity a name"} value={name} onChangeText={setName}></TextInput>
</View>
</KeyboardAvoidingView>
<TouchableNativeFeedback onPress={createActivity} background={TouchableNativeFeedback.Ripple("#fff", true)}>
<View style={style.saveButton}>
<Image style={style.saveIcon} source={require("../../assets/icons/light/save.png")}></Image>
</View>
</TouchableNativeFeedback>
</View>
</KeyboardAvoidingView>
</View>
Also see the comment in the code above. Check if you really need to use of flex: 1 in all the outer wrapper elements, and take a look to the height you are setting in the style.main based on dimentions. I don't think that it is necesary and I think it could lead to some measure issues if you fix the height of the parent container.
EDIT:
I was just digging in react-native docs and I realize that there is a zIndex that you could use to avoid ablsolute positioning. It is a relative style prop so it needs to be set between sibling views, like this:
export default class MyComponent extends React.Component {
render() {
return (
<View>
<View style={[styles.appbarShape, styles.appbarZIndex]} ><Text>Header</Text></View>
<KeyboardAvoidingView behavior="position" style={styles.contentZIndex}>
{other children}
<TextInput placeholder="enter text"/>
</KeyboardAvoidingView>
</View>
);
}
}
const styles = StyleSheet.create({
appbarShape: {
height: 80,
width: Dimensions.get('window').width,
justifyContent: 'center',
alignSelf: "stretch",
backgroundColor: "#FFF"
},
appbarZIndex: {
zIndex: 3,
},
contentZIndex: {
zIndex: 0
}
});
Since the view that represents the appbar has a greater zIndex it shows up over the ones with a lower zIndex
Check this out working in this snack https://snack.expo.io/5VXAcw4Y0
Docs: https://reactnative.dev/docs/layout-props
Hope it helps!
Use react-native-keyboard-aware-scroll-view
<KeyboardAwareScrollView extraHeight={135} enabledOnAndroid={true}
extraScrollHeight={70} style={styles.mainContainer}
automaticallyAdjustContentInsets={true}
enableOnAndroid={true}
keyboardShouldPersistTaps='handled'
scrollEnabled={true} >
//your form
</KeyboardAwareScrollView>
const styles = StyleSheet.create({
mainContainer: { flex: 1, marginHorizontal: 15, marginVertical: 15 },
});
I am trying to place a floating action button in the lower right corner of my app but it is placing it in the top left way off screen.
Returned view:
<View>
<View style={{flexDirection: 'row'}}>
<TouchableOpacity onPress={this.onPress} activeOpacity={.5} >
<Image
source={require('./assets/images/hamburger.png')}
style={{ width: 30, height: 25, marginLeft: 15}}
/>
</TouchableOpacity>
</View>
<FloatingAction style={styles.bottom}/>
</View>
Styles:
const styles = StyleSheet.create({
bottom: {
flex: 1,
position: 'absolute',
bottom: 10,
right:10
},
});
My current view displays a header and a bottom tab view. I am able to place multiple FAB's in each tab screen but that produces an undesirable behavior. Thank you for any help.
Edit:
What I have:
What I want:
Your issue was on adding { flex: 1, position: 'absolute',} to the button style together. The parent component that covers all the phone screen would use flex: 1, your button component is the one that receives the style for the position.
Always creating a new component makes stuff easier to read and understand. So let's say you have a button component (<FloatingButton/>), you would do something like this:
import React from 'react';
import { Text, View, StyleSheet } from 'react-native';
import FloatingButton from './FloatingButton';
export default class App extends React.Component {
render() {
return (
<View style={styles.container}>
<Text>
I'm just a Text
</Text>
<FloatingButton
style={styles.floatinBtn}
onPress={() => alert(`I'm being clicked!`)}
/>
</View>
);
}
}
const styles = StyleSheet.create({
container: {
flex: 1,
justifyContent: 'center',
alignItems: 'center',
},
floatinBtn: {
position: 'absolute',
bottom: 10,
right: 10,
}
});
You will get this result:
This is the button component:
import React from 'react';
import { View, TouchableOpacity } from 'react-native';
export default props => (
<TouchableOpacity onPress={props.onPress} style={props.style}>
<View
style={{
backgroundColor: 'blue',
width: 45,
height: 45,
borderRadius: 45,
}}
/>
</TouchableOpacity>
);
Check the snack demo: https://snack.expo.io/#abranhe/floating-btn
// this should occupy the whole screen
<View style={{flex:1}}>
<View style={{flexDirection: 'row'}}>
<TouchableOpacity onPress={this.onPress} activeOpacity={.5} >
<Image
source={require('./assets/images/hamburger.png')}
style={{ width: 30, height: 25, marginLeft: 15}}
/>
</TouchableOpacity>
</View>
<FloatingAction style={styles.bottom}/>
</View>
const styles = StyleSheet.create({
bottom: {
position: 'absolute',
bottom: 10,
right:10
},
});
Just use that CSS in your code:
.floating-btn {
position:fixed;
bottom:10;
right: 10;
}
That's it
I'm using react-native-lightbox for an image viewer, and when I open the image I want to take a full-screen width, but it doesn't do that; it just takes a default width before it opens. I'm using the width and height as a state and, when opening the lightbox, for updating the value, but that didn't work (it gave the error "lightbox Not Working".) So, how do I handle these images to take full width and height?
import React, { Component, Fragment } from "react";
import firebase from "react-native-firebase";
import Icon from "react-native-vector-icons/Ionicons";
import Lightbox from "react-native-lightbox";
import {
View,
Text,
StyleSheet,
TouchableOpacity,
Image,
FlatList,
ScrollView,
Dimensions
} from "react-native";
const { width, height } = Dimensions.get("window");
class GalleryScreen extends Component {
constructor(props) {
super(props);
this.state = {
images: [],
widthX: width / 3 - 17,
heightX: 110,
flexO: 0
};
}
componentDidMount() {
const uid = firebase.auth().currentUser.uid;
firebase
.database()
.ref(`providers/${uid}`)
.on("value", snapshot => {
let uri = snapshot.val().Images;
let images = [];
Object.values(uri).forEach(img => {
images.push({ uri: img.uri });
});
this.setState({ images });
});
}
render() {
return (
<View style={styles.container}>
<FlatList
numColumns={3}
key={Math.floor(Math.random() * 1000)}
data={this.state.images}
style={{
alignSelf: "center",
marginTop: 10,
marginBottom: 0
}}
renderItem={({ item }) => {
return (
<TouchableOpacity style={{ margin: 5 }}>
<Lightbox
underlayColor="#fff"
style={{ flex: 1 }}
backgroundColor="#001"
>
<Image
key={Math.floor(Math.random() * 100)}
source={{ uri: item.uri }}
style={{
alignSelf: "center",
width: width / 3 - 17,
height: 110,
borderRadius: 15
}}
resizeMethod="resize"
resizeMode="cover"
/>
</Lightbox>
</TouchableOpacity>
);
}}
keyExtractor={(item, index) => index.toString()}
/>
<TouchableOpacity
style={{
alignItems: "center",
justifyContent: "center",
alignSelf: "flex-end",
width: 70,
height: 70,
right: 20,
bottom: 15,
borderRadius: 50
// backgroundColor: "#fff"
}}
>
<Icon name="ios-add-circle" size={70} color="#2F98AE" />
{/* <Text style={{ fontSize: 40, color: "#fff" }}>+</Text> */}
</TouchableOpacity>
</View>
);
}
}
export default GalleryScreen;
const styles = StyleSheet.create({
container: {
flex: 1,
backgroundColor: "#f1f1f1"
}
});
You need to set size for outer container intead of the image and give the image with width and height 100% so that when the lightbox shows up, the image will take a full-screen size
<TouchableOpacity
key={Math.floor(Math.random() * 100)}
style={{ margin: 5, width: width / 3 - 17, height: 110 }}
>
<Lightbox
underlayColor="#fff"
style={{ flex: 1 }}
backgroundColor="#001"
>
<Image
source={{ uri: item.uri }}
style={{
borderRadius: 15,
width: "100%",
height: "100%"
}}
resizeMethod="resize"
resizeMode="cover"
/>
</Lightbox>
</TouchableOpacity>
lightBox have property called (activeProps). for make image full screen just delete style={{ flex: 1 }}. and add that property. set its value like this:
activeProps={{width: '100%', height: '100%'}}
as reference check this out : https://github.com/oblador/react-native-lightbox
I have a "fullscreen" background image that is used for a page:
container = {
flex: 1,
width: null,
height: null
}
<View ...>
...
<Image ... styles={container}>
...
<TextInput ... />
...
</Image>
</View>
However, as you may notice, tapping on the text input will open up the keyboard and the height of view changes. Since the image is set to cover, it also adjusts as the dimension of the view changes. I want the height of the parent view and the <Image> to not be affected by the keyboard, and only the content of the <Image> should be pushed up by the keyboard.
I'm aware there is a <KeyboardAvoidingView> available but I am not sure how to use it or does it even handle this situation.
Any ideas would be great. Thanks.
I do like this in React Native and it works :
backgroundImage: {
position: 'absolute',
left: 0,
top: 0,
width: Dimensions.get('window').width,
height: Dimensions.get('window').height,
},
I added
android:windowSoftInputMode="adjustPan"
to my AndroidManifest.xml and it worked out perfectly - the view doesn't get shrinked and the text inputs got pushed up.
Here's the solution I found to the same problem that I've faced. As you said, you can use react-native-keyboard-avoiding-view which is a really good way of avoiding keyboard and this solution implements that.
So what we have here is an image with style imageStyle wrapping everything.
render() {
return(
<Image source={{uri: 'blabla'}} style={imageStyle}>
<View style={styles.container}>
<KeyboardAwareScrollView>
<TouchableOpacity onPress={this.abc.bind(this)}>
<View style={styles.abc}>
<Text>Test</Text>
</View>
</TouchableOpacity>
...
</KeyboardAwareScrollView>
...
</View>
</Image>
)
}
and imageStyle:
const imageStyle = {
width: Dimensions.get('window').width,
height: Dimensions.get('window').height,
resizeMode: 'stretch',
}
Bonus: If you are going to support screen rotations, you can do:
const { width, height } = Dimensions.get('window')
const imageStyle = {
width: width < height ? width : height,
height: width < height ? height : width,
resizeMode: 'stretch',
}
Change
android:windowSoftInputMode="adjustResize"
To
android:windowSoftInputMode="adjustPan"
In android/app/src/main/AndroidManifest.xml, block activity
I wanted to accomplish the same thing, but without changing windowSoftInputMode.
I was able to do it by setting just the height of the image to Dimensions.get('window').height.
My background image stays put when the keyboard opens, but the components sitting on top of it move out of the way.
Because I was using React Navigation also, I was having issues using the window height effectively. I have a notification stuck to the bottom, and it was off the screen. My eventual solution was to close the ImageBackground element prior to the children:
<View style={styles.container}>
<ImageBackground
source={BACKGROUND}
imageStyle={{ resizeMode: 'repeat' }}
style={styles.imageBackground}
/>
<SafeAreaView style={{ flex: 1, justifyContent: 'space-between' }}>
<KeyboardAvoidingView behavior={Platform.OS === 'ios' ? "padding" : "height"} style={{flex: 1, justifyContent: 'space-between'}}>
{children}
</KeyboardAvoidingView>
<Notification/>
</SafeAreaView>
</View>
With styles looking like
export const { width: screenWidth, height: screenHeight } = Dimensions.get('window');
export const styles = StyleSheet.create(
{
notification: { position: 'absolute', bottom: 0, left: 0, right: 0, alignItems: 'stretch'},
imageBackground: { position: 'absolute', left: 0, top: 0, height: screenHeight, width: screenWidth },
container: {
flex: 1,
alignItems: 'stretch',
justifyContent: 'space-around',
},
});