React-Native: how to fill fullsize screen without explicit Width and Height? - react-native

I want to create a fullsize-screen with the child-view (a video player) that is rendered over the full size of the screen. I only get it work when i pass explicitly width and height to the component.
But i know that there is a property called "flex". In many tutorials they do something like "flex: 1", but for me it nowhere does what it is supposed to.
(For the sake of completeness, the video-player is not part of the question. I can also replace the <video> tag with <Image> or each other kind of view and get the same results)
render() {
const uri = this.props.uri
return (
<KeyboardAwareScrollView keyboardShouldPersistTaps="always" >
<TouchableWithoutFeedback onPress={RouterActions.pop}>
<Video source={{uri: uri}}
ref={(ref) => {
this.player = ref
}}
style={s.fullsize}
/>
</TouchableWithoutFeedback>
<TouchableOpacity onPress={RouterActions.pop} style={s.closeBtn}>
<Icon name="times-circle-o" size={20} color="white" />
</TouchableOpacity>
</KeyboardAwareScrollView>
)
}
My styles:
This is only working when i pass the width and height:
const s = StyleSheet.create({
fullsize: {
backgroundColor: 'black',
//flex: 1,
width: Dimensions.get('window').width,
height: Dimensions.get('window').height,
},
closeBtn: {
position: 'absolute',
left: 20,
top: 25,
},
});
I only tried out this one, but then the screen will be empty because of the -Component has a width and height of 0 each.
const s = StyleSheet.create({
fullsize: {
backgroundColor: 'black',
flex: 1, // this is not working
left: 0,
right: 0,
top: 0,
bottom: 0
},
});

I believe doing flex: 1 will make it take up all the space provided by it's parent element. In your case, none of your parent elements have any styling so try this out:
render() {
const uri = this.props.uri
return (
<View style={{ flex: 1 }}>
<TouchableWithoutFeedback style={{ flex: 1 }} onPress={RouterActions.pop}>
<Video source={{uri: uri}}
ref={(ref) => {
this.player = ref
}}
style={{ flex: 1 }}
/>
</TouchableWithoutFeedback>
<TouchableOpacity onPress={RouterActions.pop} style={s.closeBtn}>
<Icon name="times-circle-o" size={20} color="white" />
</TouchableOpacity>
</View>
)
}

Related

React native animation progress bar with image

Today i want to make a progress bar with a image on the left. Unfortunately I can't position the image in the right place. For now it looks like that
I want to looks something like that -
My code so far -
<View
style={{
flexDirection: "row",
alignSelf: "center",
marginBottom: "20%",
marginTop: "10%",
}}
>
<View
style={{
width: "90%",
height: 30,
padding: 2.5,
backgroundColor: "#00000020",
borderRadius: 30,
}}
>
{/* <Animated.View
style={[
{
width: "100%",
height: 25,
borderRadius: 15,
backgroundColor: "#f5de41",
},
{
width: progressAnim,
},
]}
></Animated.View> */}
<Image
source={require("./assets/lion.png")}
style={{
height: 44,
height: 44,
position: "absolute",
}}
resizeMode="contain"
/>
</View>
</View>
I tried to add left: '-62%' in style of iamge but it not works. I am not sure how to move the lion to the left?
One approach would be to remove the absolute position and use flexbox to align the the image to end of the row:
const ProgressBar = ({imgSource,imgStyle,imgSize,style,progress,color})=>{
let loadingAnim = useRef(new Animated.Value(progress)).current;
const [{width,height},setViewDimensions] = useState({});
// get parent view size
const onLayout=({nativeEvent})=>{
setViewDimensions({
width:nativeEvent.layout.width,
height:nativeEvent.layout.height
})
}
const animatedWidth =loadingAnim.interpolate({
inputRange:[0,1],
outputRange:[0,width-imgSize],
extrapolate:'clamp'
})
const containerAnimation = {
margin:0,
padding:0,
width:Animated.add(animatedWidth,imgSize),
backgroundColor:color,
height:'100%',
justifyContent:'center',
overflow:'hidden'
}
useEffect(()=>{
Animated.timing(loadingAnim,{
toValue:progress,
duration:100
}).start()
},[progress])
return(
<View style={[styles.loadingContainer,{height:imgSize*1.5||null},style]} onLayout={onLayout}>
<Animated.View style={[styles.loadingContainer,containerAnimation]}>
<Animated.Image
source={imgSource}
style={[{height:imgSize,width:imgSize,alignSelf:'flex-end'},imgStyle,{}]}
/>
</Animated.View>
</View>
)
}
I found this approach to be slightly un-smooth. I think this is because the width of image's parent view was being animated, and not the actual position of the image.
Another approach would be to animate the image:
const ProgressBar = ({imgSource,imgStyle,imgSize,style,progress,color})=>{
let widthAnim = useRef(new Animated.Value(progress)).current;
const [{width,height},setViewDimensions] = useState({});
// get parent view width to determine progress view size
const onLayout=({nativeEvent})=>{
setViewDimensions({
width:nativeEvent.layout.width,
height:nativeEvent.layout.height
})
}
const animatedWidth = widthAnim.interpolate({
inputRange:[0,1],
outputRange:[0,width-imgSize],
extrapolate:'clamp'
})
const containerAnimation = {
// min width will be imgSize
width:Animated.add(animatedWidth,imgSize),
backgroundColor:color,
}
const imgAnimation = {
left:animatedWidth
}
// animate progress changess
useEffect(()=>{
Animated.timing(widthAnim,{
toValue:progress,
duration:100
}).start()
},[progress])
return(
<View>
<View style={[styles.loadingContainer,{height:imgSize*1.25||null},style]} onLayout={onLayout}>
<Animated.View style={[styles.progressBar,containerAnimation]}/>
</View>
<Animated.Image
source={imgSource}
style={[styles.image,{height:imgSize,width:imgSize},imgStyle,imgAnimation]}
resizeMode='contain'
/>
</View>
)
}

onPress event not working inside the Animated View when it's position is absolute

I'm building a custom header. onPress event of the touchable opacity component is not working when I give components style prop - 'position:"absolute"' . But it works perfectly when I comment on the style property - position.
I couldn't find a solution for this elsewhere. Please help.
<Animated.View
style={{
elevation:
params !== undefined && params.elevation !== undefined
? params.elevation
: null,
position: "absolute",
top: 0,
left: 0,
backgroundColor:
params !== undefined && params.headerBgColor !== undefined
? params.headerBgColor
: "red",
width: "100%",
height:
params !== undefined && params.changingHeight !== undefined
? params.changingHeight
: 50,
justifyContent: "space-between",
alignItems: "center",
flexDirection: "row",
paddingHorizontal: 20
}}
>
<TouchableOpacity style={{}} onPress={() => console.log("hello")}>
<View style={{}}>
<Image
style={styles.menuIcon}
source={require("../../assets/images/Menu-512.png")}
/>
</View>
</TouchableOpacity>
<TouchableOpacity onPress={() => console.log("image")}>
<View style={{}}>
<Image
style={styles.profImage}
source={require("../../assets/images/user.png")}
/>
</View>
</TouchableOpacity>
</Animated.View>;
You should put your absolutely positioned Animated.View as the last child in the screen component. Otherwise, the view that occupies the rest of the screen will become the responder to touches.
const Screen = () => {
return <View style={{ flex: 1}}>
<View style={{flex: 1}}>
//actual screen content
</View>
<Animated.View // header
...props
></Animated.View>
</View>
In the DOM, the component that comes after another component is put "above" it. So, if you do this, your header will be above the actual screen content view and, therefore, become the responder when pressed.
its working on my case checkout below code:
or checkout my snack example : https://snack.expo.io/#immynk/header_demo
either you missing some params which are providing or getting null on condition check kindly confirm it hope this answer will help you
import * as React from 'react';
import {
Text,
View,
StyleSheet,
Animated,
TouchableOpacity,
Image,
} from 'react-native';
import Constants from 'expo-constants';
export default class App extends React.Component {
render() {
return (
<View>
<Text>Hello this is demo of flexdirection of box color</Text>
<Animated.View
style={{
position: 'absolute',
top: 0,
left: 0,
backgroundColor: 'red',
width: '100%',
height: 50,
justifyContent: 'space-between',
alignItems: 'center',
flexDirection: 'row',
paddingHorizontal: 20,
}}>
<TouchableOpacity style={{}} onPress={() => alert("hello","hello")}>
<View style={{}}>
<Image
source={{ uri: 'https://reactjs.org/logo-og.png' }}
style={{ width: 50, height: 65 }}
/>
</View>
</TouchableOpacity>
<TouchableOpacity style={{}} onPress={() => alert("hello","hello")}>
<View style={{}}>
<Image
source={{ uri: 'https://reactjs.org/logo-og.png' }}
style={{ width: 50, height: 65 }}
/>
</View>
</TouchableOpacity>
</Animated.View>
</View>
);
}
}

React-Native-Swiper images Overflow ONLY ON ANDROID

I have a problem with react-native-swiper on Android ONLY. The same code works for iOS!
Below is an image of what is happening:
The area is blue is supposed to be a square and all images should be within it. Something like this (I only render 1 image here):
This is what my code looks like:
renderSwiper = () => {
const images = this.props.data.item[1].images;
let swiperImages = images.map((image, index) => {
let priority = FastImage.priority.normal;
if (index === 0)
priority = FastImage.priority.high;
return (
<TouchableWithoutFeedback key={index} onPress={this.routeToListingDetails} >
<FastImage
style={styles.imageStyle}
source={{uri: image, priority: priority}}
/>
</TouchableWithoutFeedback>
)
})
return (
<View style={{ aspectRatio: 1, width: '100%'}}>
<Swiper
loop={false}
paginationStyle={styles.swiperPaginationStyle}
>
{swiperImages}
</Swiper>
</View>
);
}
render(){
return (
<View style={styles.container} >
<View style={{ borderColor: 'blue', borderWidth: 2 }}>
{this.renderSwiper()}
</View>
</View>
)
}
const styles = StyleSheet.create({
container:{
width:'50%',
alignItems:'center',
marginBottom:'4%',
padding:'2%',
},
imageStyle:{
resizeMode: "cover",
width: "100%",
aspectRatio:1
}
})

react native flatlist 2 items per row , width not equal

I build react native app and I'm trying to make 2 items per row with equal width in flatList.
what I get it's 2 items per row but not equal width.
const itemProduct = props => {
return (
<Button style={style.container} onPress={props.onPress}>
<View style={style.imageContainer}>
<LoadingImage resizeMode='contain' resizeMethod='resize' source={props.Image ? { uri: 'https://www.saramashkim.co.il/'+props.Image } : require('../../assets/images/default_no_image.png')} style={style.image} />
</View>
<View style={style.textContainer}>
<Text style={style.productName}>vodka</Text>
<View style={style.specialOffer}>
{props.inPromotion ? <Text>special offer</Text> : null}
</View>
<View style={style.bottomLine}>
<Text style={style.costText}>lorem ipos</Text><View style={style.bottomLine}>{props.discount ? <Text style={style.Price}>lorem ipos{parseFloat(Math.round(props.price_per_case * 100) / 100).toFixed(2)}</Text> : null}<Text style={style.discountPrice}>dollar{parseFloat(Math.round(props.price_per_case * ((100 - props.discount) / 100) * 100) / 100).toFixed(2)}</Text></View>
</View>
</View>
</Button>
)
}
style
const style = StyleSheet.create({
container : {
backgroundColor: colors.dark_red,
paddingTop:calcSize(10),
margin:calcSize(10),
minWidth:(width-15)/2,
},
imageContainer:{
flex:1,
alignItems:'center'
},
textContainer:{
flex:2,
//backgroundColor:'red',
paddingHorizontal:calcSize(30)
},
image:{
width: calcSize(175),
height: calcSize(175)
},
brandName:{
color:'#7c7c7c',
fontFamily:'Poppins-Light',
fontSize:calcSize(25),
marginBottom:calcSize(15)
},
productName:{
color: colors.black,
fontFamily:'Poppins-Regular',
fontSize:calcSize(20),
width:calcSize(300)
},
flatList
<View style={style.list}>
<FlatList
refreshing={this.state.refreshing}
numColumns = {2}
onRefresh={this.onListRefresh}
data={products}
keyExtractor={(o, i) => i.toString()}
renderItem={this.renderProductListItem}
ListFooterComponent={() => {
if ((this.state.products.length < this.state.totalFound || this.state.loading) && !this.state.refreshing)
return <Spinner style={style.loading} />
return <View style={style.loading} />
}}
ItemSeparatorComponent={() => <View style={style.separator} />} />
</View>
</View>
list style
list:{
flex:1,
flexDirection:'row',
paddingHorizontal: calcSize(30),
}
photo
I want to make 2 item per row with equal width, also into the photo as you can see the text in left not equal to the right so it's issue.
Use flexbox with flexbasis and flex grow try this
<View style={{flex: 1, flexDirection: 'row', flexWrap: 'wrap', flexGrow: 0}}>
<View style={{flexBasis: '50%', height: 50, backgroundColor: 'powderblue'}} />
<View style={{flexBasis: '50%', height: 50, backgroundColor: 'skyblue'}} />
<View style={{flexBasis: '50%', height: 50, backgroundColor: 'steelblue'}} />
<View style={{flexBasis: '50%', height: 50, backgroundColor: 'blue'}} />
</View>
Tested in my android device.
Live demo is over here! Give this a try
If any issue comment that down below
Right now you've exclusively set the width of the child element as minWidth:(width-15)/2, the margin as margin:calcSize(10),
padding for the main container as paddingHorizontal: calcSize(30) which is causing the issue .
If you want to go the minWidth way, then you need to calculate the spacing correctly
minWidth = (screenWidth - (paddingHorizontal * 2) - (margin * 2) - (separatorWidth)) / 2 = (screenWidth - 80) / 2
Since there is no separatorWidth mentioned in the question
paddingHorizontal: Setting paddingHorizontal is like setting both of paddingLeft and paddingRight.
margin:
Setting margin has the same effect as setting each of marginTop, marginLeft, marginBottom, and marginRight.
list:{
flex:1,
paddingHorizontal: calcSize(30),
},
container : {
flex: 1, //<== Either add a height or a flex
backgroundColor: 'darkred',
paddingTop:calcSize(10),
margin:calcSize(10),
minWidth:(width-80)/2,
},
Better approach would be to use height and flex , so that width can be scaled accordingly.
Here's a snack demo

How do i set a background image to custom DrawerNavigator in react-navigation

My issue is, that i want the image is overflowing the Drawer
and does not fit the view width
I use contentComponent to have a custom Drawer.
the answer in the link below shows kinda what i want to achieve.
The issue though is, that width and heigth are given in absolute
values. This won't be working for tablet, iphones and android phones.
Any ideas?
export default StyleSheet.create({
...ApplicationStyles.screen,
container: {
//marginTop: Metrics.navBarHeight,
flex: 1,
flexDirection: 'column',
alignItems: 'stretch',
},
contentContainer: {
backgroundColor: 'transparent'
},
drawerImage: {
position: 'absolute',
top: 0,
left: 0,
right: 0,
bottom: 0,
opacity: 0.05,
backgroundColor: 'green'
// resizeMode: "stretch"
},
render () {
const { navigation } = this.props
return (
<View style={styles.container}>
<Image source={Images.drawerBackground} style={styles.drawerImage}/>
<ScrollView style={styles.contentContainer}>
<SafeAreaView forceInset={{ top: 'always', horizontal: 'never' }}>
<DrawerButton
iconName='ios-map'
text='Map'
onPress={() => navigation.navigate('MapView')}
/>
<DrawerButton
iconName='md-trending-up'
text='Elevation'
onPress={() => navigation.navigate('Elevation')}
/>
<DrawerButton
iconName='md-people'
text='Friends'
onPress={() => navigation.navigate('Friends')}
/>
<DrawerButton
iconName='md-person'
text='Profile'
onPress={() => navigation.navigate('Profile')}
/>
<DrawerButton
iconName='md-settings'
text='Settings'
onPress={() => navigation.navigate('Settings')}
/>
<View style={styles.checkinBtn}>
<CheckinButton
iconName='md-pin'
text='Checkin Location'
onPress={() => navigation.navigate('Settings')}
/>
</View>
</SafeAreaView>
</ScrollView>
<View style={styles.footer}>
<Text style={styles.text}>
........
</Text>
</View>
</View>
)
}
}
How to set a background Image of Navigator in React-Native
try using ImageBackground instead of Image and wrap all your elements into it
Refer the official docs here
import { ImageBackground } from "react-native";
<ImageBackground source={require('../../assets/images/AImg.png')} style={{ width: 100, height: 100}}>
//ur view/text flows here.....
</ImageBackground>
import and add ImageBackground
https://facebook.github.io/react-native/docs/images.html#background-image-via-nesting