Aligning items with flexbox in react native - css

I'm trying to align Views in React Native, and I want that every View is 50% of the screen. Something like :
My state is :
this.state = {
companies: [
{logo_url: require("../../../img/company_logos/ald.png")},
{logo_url: require("../../../img/company_logos/arval.png")},
{logo_url: require("../../../img/company_logos/businesslease.png")},
{logo_url: require("../../../img/company_logos/dieterenusedcars.png")},
{logo_url: require("../../../img/company_logos/psa.png")},
{logo_url: require("../../../img/company_logos/remarketing_center.png")},
{logo_url: require("../../../img/company_logos/vdfin.png")}
]
}
And then in the render method :
render(){
return (
<View style={{flex: 1, flexDirection: 'row'}}>
{this.state.companies.map(company => {
return (
<View style={{width: Dimensions.get('window').width * 0.5, height: 150}}>
<Image source={company.logo_url} style={{width: Dimensions.get('window').width * 0.5, height: 100}}/>
</View>
);
})}
</View>
)
}
But I see only first two logos.
All items are probably shown in one row instead of going to second row if there is no more place on the screen.
Any advice?

In case somebody else has the same problem.
I solved it by adding flexWrap: "wrap" to the parent View
<View style={{flex: 1, flexDirection: 'row', flexWrap: "wrap"}}>

Related

creating flatlist grid from api data [duplicate]

This question already has answers here:
CSS Grid - 2x2 grid always taking up the full width when possible
(1 answer)
How to set up a dynamic grid based on flex or grid
(1 answer)
Closed yesterday.
I want to create a dynamic grid in the flatlist, but it is not dynamic when data increases, my data is an array of object which has images and other information too.
I am using
columnWrapperStyle={{flexWrap: 'wrap', flex: 1 / 2}}
width: "100%",
height: height / 2.3,
I want to create something like this
if there is one image the grid should cover full width and if two images it should take half of width,
now the main issue I want to do something when there are three images the first height should be full and others will divide the height in half, same for the last one.
thanks.
You should use or get inspired by this package - https://www.npmjs.com/package/react-native-fb-image-grid
import React, { Component } from "react";
import { StyleSheet, View } from "react-native";
import FbGrid from "react-native-fb-image-grid";
class App extends Component {
render() {
return (
<View style={styles.container}>
<View style={styles.inner_container}>
<FbGrid
images={[
"https://facebook.github.io/react-native/docs/assets/favicon.png",
]}
/>
</View>
<View style={styles.inner_container}>
<FbGrid
images={[
"https://facebook.github.io/react-native/docs/assets/favicon.png",
"https://facebook.github.io/react-native/docs/assets/favicon.png",
]}
/>
</View>
<View style={styles.inner_container}>
<FbGrid
images={[
"https://facebook.github.io/react-native/docs/assets/favicon.png",
"https://facebook.github.io/react-native/docs/assets/favicon.png",
"https://facebook.github.io/react-native/docs/assets/favicon.png",
]}
/>
</View>
<View style={styles.inner_container}>
<FbGrid
images={[
"https://facebook.github.io/react-native/docs/assets/favicon.png",
"https://facebook.github.io/react-native/docs/assets/favicon.png",
"https://facebook.github.io/react-native/docs/assets/favicon.png",
"https://facebook.github.io/react-native/docs/assets/favicon.png",
"https://facebook.github.io/react-native/docs/assets/favicon.png",
"https://facebook.github.io/react-native/docs/assets/favicon.png",
]}
/>
</View>
</View>
);
}
}
const styles = StyleSheet.create({
container: {
flex: 1,
alignItems: "center",
justifyContent: "center",
backgroundColor: "#eee",
},
inner_container: {
width: "100%",
height: "20%",
},
});
export default App;
Live Demo - https://snack.expo.dev/#emmbyiringiro/c182c6

How to make scroll view scroollabe inside panGestureHandler?

I am using a react-native-gesture-handler library with reanimated and react-native-redash. I want to make scrollView scrollable which is nested inside panGestureHandler but all the interactions are handled by panGestureHandler, so scrollView is not working. Here is my code.
VideoModal.js file
import Animated , {useCode , cond , eq , set , add, block, interpolate, Extrapolate} from "react-native-reanimated"
import {PanGestureHandler , State } from "react-native-gesture-handler"
import {usePanGestureHandler , useValue , timing , snapPoint} from "react-native-redash/lib/module/v1"
export default function VideoModal(props) {
const { video } = props;
const {gestureHandler , velocity , translation , state} = usePanGestureHandler()
const translateY = useValue(0)
const offsetY = useValue(0);
const snapPoints = snapPoint(translateY , velocity.y , [0 ,upperBound])
useCode(()=>block([
cond(
eq(state , State.ACTIVE),
[
set(translateY , add(offsetY , translation.y))
]
),
cond(
eq(state , State.END),
[
set(translateY , timing({from:translateY , to:snapPoints, duration:350})),
set(offsetY , translateY)
]
)
]))
return (
<>
<View
style={{
height: statusBarHeight,
backgroundColor: 'black',
}}
/>
<PanGestureHandler {...gestureHandler} >
<Animated.View
style={{
...shadow,
transform:[{translateY:translateY}],
zIndex:10
}}
>
<TouchableWithoutFeedback onPress={()=>alert('Working'}>
<View style={{ backgroundColor: 'white', width }}>
<View style={{ ...StyleSheet.absoluteFillObject }}>
<PlayerControls title={video.title} onPress={() => alert('abc')} />
</View>
<AnimatedVideo
source={video.video}
style={{ width, height:videoContent }}
resizeMode={Video.RESIZE_MODE_COVER}
shouldPlay
/>
</View>
</TouchableWithoutFeedback>
<Animated.View style={{ backgroundColor: 'white', width:contentWidth, height:contentHeight }}>
<Animated.View style={{opacity:contentOpacity}}>
**<VideoContent {...{ video }} />**
</Animated.View>
</Animated.View>
</Animated.View>
</PanGestureHandler>
</>
);
}
the scrollView is inside VideoContent
import {
View, StyleSheet, Text, Image, ScrollView,
} from 'react-native';
export default function VideoContent(props) {
const { video } = props;
return (
<ScrollView>
<View style={styles.upNext}>
<Text style={styles.upNextTitle}>Up next</Text>
{
videos.map(v => (
<View key={v.id} style={styles.thumbnail}>
<Image source={v.thumbnail} style={styles.thumbnailImage} />
<View style={styles.thumbnailContent}>
<Text numberOfLines={2} style={styles.thumbnailTitle}>{v.title}</Text>
<Text style={styles.thumbnailUsername}>{v.username}</Text>
</View>
</View>
))
}
</View>
</ScrollView>
);
}
Is there anyway I can tell pangesture to work only if the finger is placed on the top part of screen otherwise it should not work and i can scroll the content present inside the scrollview??
Hey i Know its bit late to reply to your answer but i also faced the similar issue, a bit of research unable to me find this trick
activeOffsetX={[-10, 10]}
in you pangestureHandler like this
<PanGestureHandler
onGestureEvent={onGestureEvent}
activeOffsetX={[-10, 10]}
onHandlerStateChange={evt =>handleStateChange(evt)}
>
source : https://www.gitmemory.com/issue/software-mansion/react-native-gesture-handler/1380/786721032
I hope it helps

How do I conditonally add wrapper in loop React?

Actually my question is about React Native, but i think it's similar to React.
I'm tried to create dynamic menu with loop in array like this:
My question is: how do I conditionally add another <View/> while using map?
let say there's 4 value in array and I've tried to do something like this:
_renderMenu(){
let menu = this.state.menu.map((el, index)=>{
if(index==0){
return(
<View style={{flex:1, margin:5, borderRadius:5, backgroundColor:Color.amber_200}}/>
)
} else {
//Wrap the rest with <View style={MyStyle}>
return(
<View style={{flex:1, margin:5, borderRadius:5, backgroundColor:Color.amber_200}}/>
)
//</View>
}
})
return(
<View style={{flex:1, padding:5}}>
{menu}
</View>
)
}
My loop pattern something like this:
<View style={{flex:1, margin:5, borderRadius:5, backgroundColor:Color.amber_200}}/>
<View style={{flexDirection:'row', flex:1}}> //if index!==0 wrap the rest with this view
<View style={{flex:1, margin:5, borderRadius:5, backgroundColor:Color.amber_200}}/>
<View style={{flex:1, margin:5, borderRadius:5, backgroundColor:Color.amber_200}}/>
<View style={{flex:1, margin:5, borderRadius:5, backgroundColor:Color.amber_200}}/>
</View>
Is it possible to conditionally something like my case?
Based on the above comments, here's a solution for your problem:
First, you'll need to add lodash to the project to use the _.chunck method: https://lodash.com/docs/4.17.11#chunk
_renderMenu() {
const menuItem = (item, index) => (
<View key={`menu_item_${index}`} style={{ flex: 1, margin: 5, borderRadius: 5, backgroundColor: Color.amber_200 }}>{item}</View>
)
const splitArray = _.chunk(this.state.menu.slice(1), 3)
return (
<View style={{ flex: 1, padding: 5 }}>
{menuItem(this.state.menu[0], 0)}
{
splitArray.map((array, index) => {
return (
<View style={{ flexDirection: 'row', flex: 1 }}>
{array.map((element, elementIndex) => menuItem(element, (elementIndex * index) + elementIndex + 1))}
</View>
)
})
}
</View>
)
}
the splice will skip the specified number of elements, in our case, the first one. We will render the first menu item alone, then will render the other items.
Now for the key, i'm trying to keep it unique using the * + formula to generate them based on both indexes.

How do i align react-native buttons in a horizontal row

I have 8 buttons which i would like to align in horizontal row, side by side. everything i have tried hasn't worked and the just display one on top of another.
Here's what i have at the mo.
Thanks
categories: ['art', 'funny', 'inspire', 'life', 'love', 'management', 'sports', 'students'],
render() {
let cat = this.state.categories.map((value, key) => {
return (
<View style={styles.catButtons}>
<TouchableOpacity
style={styles.buttonContainer}
key={key}
activeOpacity={0.7}
>
<Button style={styles.button}
color={'darkslategrey'}
key={key}
title={value}
onPress={() => { this.getCategoryQuote(value) }}
/>
</TouchableOpacity>
</View>
)
})
return (
<View>
{cat}
</View>
)
}
const styles = StyleSheet.create({
catButtons: {
flexWrap: 'wrap'
},
buttonContainer: {
width: 125,
margin: 10
},
});
I think, in this case, the flex items are the buttons. But the problems lies in the flex container: TouchableOpacity.
As your code suggest, there is one flex container for one button, and that is repeated by the map function.
It should be one flex container for all flex items (buttons). That means, the flex container should be outside of your map function and the items directly as its children (that are mapped by the map function).

React Native flex not giving height to component

I'm trying to create something like this:
The sections labeled with Dates, Time are where my the data from my dates and timeSpan will go. The red area is where my calendar would be placed.
I have been trying to fit Views to look like tables, but it has not been working out so well. Here's my code:
<ScrollView>
<View>...</View>
<View **
style={{
marginHorizontal: 10,
marginTop: 10,
flex: 1,
borderColor: Colors.separatorColor,
borderWidth: StyleSheet.hairlineWidth}}>
<View style={{
flex: 1,
flexDirection: 'row',
borderBottomWidth: StyleSheet.hairlineWidth,
borderBottomColor: '#EDEDED'}}>
<View style={{1, backgroundColor: '#ff0000'}}/>
{
dates.map((date, i) => {
<View key={i} style={{
flex:1,
backgroundColor: '#00fff0',
borderRightColor: '#EDEDED',
borderRightWidth: StyleSheet.hairlineWidth}}>
<Text>{date}</Text>
</View>
})
}
<View style={{flex: 1, backgroundColor: '#ff0000'}}/>
</View>
{
timeSpan.map((time,i) => {
<View style={{
flex: 1,
flexDirection: 'row',
borderBottomWidth: StyleSheet.hairlineWidth,
borderBottomColor: '#EDEDED'}}>
<View style={{flex: 1, backgroundColor: '#ff0000'}}/>
<View style={{flex: 1, backgroundColor: '#ff0000'}}/>
</View>
})
}
</View>
<View>...</View>
</ScrollView>
The <View>...</View> is the code for Other Stuff that will just make my question look much longer so I cut it out. I'm trying to make the <View>s look like a table which have dates.length columns and timeSpan.length rows.
The issue right now is that nothing appears on my screen when I give flex: 1 to my View that I marked in the code with **. However, if I give it a fixed height such as height: 260, then I get one big fat red box instead of seeing many Views that would make up my custom calendar.
I have put in static data to dates and timeSpan and checked by logging that the iterations are done over these arrays so I am confident that the rows and columns are being created but they are not shown on the screen.
How would I resolve this issue which I believe is caused by the flex values?
EDIT:
here's a snack example of my app:
<div data-snack-id="#ohnu93/tenacious-marshmallows" data-snack-platform="ios" data-snack-preview="true" data-snack-theme="light" style="overflow:hidden;background:#fafafa;border:1px solid rgba(0,0,0,.08);border-radius:4px;height:505px;width:100%"></div>
<script async src="https://snack.expo.io/embed.js"></script>

Resources