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).
Related
I'm experiencing a lot of difficulty trying to implement a "double modal", i.e. two modals at the same time.
e.g.
I'm using Overlay from the 'react-native-elements' library to achieve the modal effect, however, putting two of them together in a view isn't working as it will only display the first one. I'm also finding that directly setting the height of the overlay isn't having any effect.
I then considered creating a custom component but can't figure out how to dim the background using CSS.
If you want, change the your element modal to react-native-modal. Keep try and execute the below code. I hope it'll work for you.
import Modal from 'react-native-modal';
const [isModalVisible, setModalVisible] = useState(false);
const toggleModal = () => {
setModalVisible(!isModalVisible);
};
<TouchableOpacity onPress={toggleModal}>
<Text>Button Text</Text>
<Modal
isVisible={isModalVisible}
onBackdropPress={() => setModalVisible(false)}>
<View style={{ backgroundColor: 'white', padding: 20, height:250 }}>
<Text>First box content appear here</Text>
</View>
<View style={{ backgroundColor: 'white', padding: 20, height:100, marginTop: 30 }}>
<Text>Second box content appear here</Text>
</View>
</Modal>
</TouchableOpacity>
When attempting to use ScrollView it appears to not respect justifyContent of its parent container.
import React from 'react';
import { Text, ScrollView, StyleSheet, TextStyle, View, ViewStyle } from 'react-native';
interface TODO_TextCard {
text: string,
}
export const TODO_TextCard: React.FunctionComponent<TODO_TextCard> = (props: TODO_TextCard) => {
return <View style={styles.viewStyle}>
<ScrollView>
<Text style={styles.quoteTextStyle}>{props.text}</Text>
</ScrollView>
</View>;
}
const styles = StyleSheet.create({
quoteTextStyle: {
fontSize: 30,
fontStyle: 'italic'
} as TextStyle,
viewStyle: {
flex: 1,
borderWidth: 2, borderColor: 'red',
justifyContent: 'center',
paddingHorizontal: 10
} as ViewStyle,
});
<TODO_TextCard text={'The mind adapts and converts to its own purposes the obstacle to our acting. The impediment to action advances action. What stands in the way becomes the way'}/>
Rendered as:
Now if I remove the and just render text such as
export const TODO_TextCard: React.FunctionComponent<TODO_TextCard> = (props: TODO_TextCard) => {
return <View style={styles.viewStyle}>
<Text style={styles.quoteTextStyle}>{props.text}</Text>
</View>;
}
The Text element does respect the justifyContent:center of the parent and renders as:
Is it possible for Scroll view to be centered?
The solution that I have in mind right now is to check the length of the text and conditionally render Scroll View something like:
/** This some text length would have to be different depending on the device screen, and
* even with different device screens would still not work all the time if the text
* can have new lines in it.*/
const SOME_TEXT_LENGTH = 300;
export const TODO_TextCard: React.FunctionComponent<TODO_TextCard> = (props: TODO_TextCard) => {
return <View style={styles.viewStyle}>
{props.text.length > SOME_TEXT_LENGTH ?
<ScrollView>
<Text style={styles.quoteTextStyle}>{props.text}</Text>
</ScrollView>
:
<Text style={styles.quoteTextStyle}>{props.text}</Text>
}
</View>;
}
Which very much is not ideal, due to different device screens as well as text potentially having new lines.
The ScrollView does in fact respect the justifyContent:center of its parent. The ScrollView is placed in the center of the outer View component. But here the ScrollView takes up the whole vertical screen, so it seems like it is not centered.
Try setting <ScrollView style={{backgroundColor: 'green'}}> to see what i mean.
Try applying viewStyle or a similar styling to the ScrollView itself. Make sure that you use the attribute contentContainerStyle instead of style. This snippet works for me.
<View style={styles.viewStyle}>
<ScrollView contentContainerStyle={{flex: 1, justifyContent: 'center'}}>
<Text style={styles.quoteTextStyle}>{props.text}</Text>
</ScrollView>
</View>
I also found this article. Maybe it will also help you out.
You need to give styling to ScrollView, for styling ScrollView you can use style or contentContainerStyle prop:
style defines the outer container of the ScrollView, e.g its height and relations to siblings elements
contentContainerStyle defines the inner container of it, e.g items alignments, padding, etc
In your case you need to give contentContainerStyle to position your items for eg:
return (
<View style={styles.viewStyle}>
{props.text.length > SOME_TEXT_LENGTH ?
<ScrollView
contentContainerStyle={{
flex: 1, //To take full screen height
justifyContent: 'center',
alignItems: 'center,
}}>
<Text style={styles.quoteTextStyle}>{props.text}</Text>
</ScrollView>
:
<Text style={styles.quoteTextStyle}>{props.text}</Text>
}
</View>
);
On android emulator, my React Native 0.62.2 app displays uploaded images within an accordion whose display area is warped with <View> which is styled with width and height. The image is warped with which is <Image> with cache ability. The problem is that the image is positioned way below beyond the viewing boundary and is not visible when open the accordion.
Here is the render code in accordion which is provided with both width and height as canvas:
return (
<>
<TouchableWithoutFeedback onPress={() => toggleListItem()}>
<View style={styles.titleContainer}>
<Text>{title}</Text>
<Animated.View style={{ transform: [{ rotateZ: arrowAngle }] }}>
<Icon name="chevron-down-outline" size={20} />
</Animated.View>
</View>
</TouchableWithoutFeedback>
<Animated.View style={[styles.bodyBackground, { height: bodyHeight }]}>
<View
style={(absPosition ? styles.bodyContainerAbs : styles.bodyContainerCenter), (screenSize ? {width:screenSize.width, height:screenSize.height, flex:1} : null)}
onLayout={event => {
if (screenSize) {
setBodySectionHeight(screenSize.height);
} else {
setBodySectionHeight(event.nativeEvent.layout.height);
};
console.log("layout : ", event.nativeEvent.layout);
}
}> //<<<===here is <View> warping the image area. Both width and height are set.
{children} //<<<===images uploaded displayed here
</View>
</Animated.View>
</>
);
const styles = StyleSheet.create({
bodyBackground: {
backgroundColor: '#EFEFEF',
overflow: 'hidden',
},
bodyContainerCenter: { //<<<==here is the style used for display images
padding: 1,
paddingLeft: 0,
justifyContent: 'center',
alignItems: 'center',
},
bodyContainerAbs: {
padding: 5,
paddingLeft: 10,
position: 'absolute',
bottom: 0,
},
});
Here is the image render code:
const displayImg = (img_source, width, ht, index) => {
if (img_source && img_source!==[] && img_source!=={}) {
return (
<ImageZoom cropWidth={screen_width}
cropHeight={screen_ht}
imageWidth={width}
imageHeight={ht}
enableSwipeDown={true}
style={{padding:1}}
>
<FastImage
source={{uri:img_source}}
resizeMode={FastImage.resizeMode.contain}
style={{ //<<<===image width and height are set
width:width,
height:ht,
position:"absolute" //<<<===does not work
}}
/>
</ImageZoom>
);
} else {
return null;
};
};
When there is one image, it is display with full screen width. For 2 images, then they are displayed side by side occupying half of the screen width:
import { Col, Row, Grid } from 'react-native-easy-grid';
const DisplayImages = ({pics}) => {
if (!pics || pics===[] || pics==={}) return null;
var len = pics.length,
if (len > 0) setImgAccordOpen(true);
switch(len) {
case 0:
return;
case 1: //<<<=== one image is uploaded
return (
<React.Fragment>
{displayImg(pics[0].path, screen_width*full, screen_width*full, 0)}
</React.Fragment>
);
case 2: //<<<=== case of 2 images uploaded
return (
<Grid style={{position:"absolute", paddingTop:0,paddingLeft:0}}>
<Row style={{paddingTop:0}}>
<Col style={{position:"absolute", top:0,left:0, paddingVertical:0}} > //<<==positioned at [0,0] on up left corner.
{displayImg(pics[0].path, screen_width*half, screen_width*half, 0)}
</Col>
<Col style={{position:"absolute", top:0,left:Math.ceil((screen_width-20)/2), paddingTop:0}}> //<<==positioned at [0, middle of screen]
{displayImg(pics[1].path, screen_width*half, screen_width*half, 1)}
</Col>
</Row>
</Grid>
);
.....
Here is the screen shot when one image is uploaded. The image is not positioned at absolute
Here is the screen shot when 2 images are uploaded. The first image is not within the viewing area and not visible at all.
How to position images right within viewing area?
The problem is the <ImageZoom> is not compatible with <FastImage> and only show a portion of image or positioning images way below the viewing screen. After removing <ImageZoom>, then the position of the images is back to normal as style dictated. Another module #dudigital/react-native-zoomable-view works fine with <FastImage>.
This seems like an easy question at first but it's actually tricky.
Better to go directly to the example. I've created a snack with the sample code here https://snack.expo.io/BkSNtNrWV
I want to have a list of items with given aspect ratio (say 3:2) and the items should take as much space as possible with a maximum limit on size. This sample code does it:
<View>
<FlatList style={{backgroundColor:'lightgray'}}
data={[{key: 'a'},{key: 'b'}]}
renderItem={({item}) =>
<View style ={styles.pink}></View>
}/>
</View>
const styles = StyleSheet.create({
pink: {
backgroundColor: "#A37E93",
maxHeight: 150,
aspectRatio: 3/2,
borderWidth: 1,
}});
And this is the result:
However, the problem is that I would like to have the items aligned to the center. I tried to wrap the list item in a flexbox with 'row' direction but that caused the item to have 0 height => not displayed. Justify content didn't help either (it's possible that I do it incorrectly).
Does anyone know how to solve this please?
Updated the code. Add flex to inner item and wrap the view inside another with screen width.
import * as React from 'react';
import { Text, View, StyleSheet,FlatList,Dimensions } from 'react-native';
import { Constants } from 'expo';
const{width} = Dimensions.get('window')
// You can import from local files
import AssetExample from './components/AssetExample';
// or any pure javascript modules available in npm
import { Card } from 'react-native-paper';
export default class App extends React.Component {
render() {
return (
<View>
<FlatList style={{backgroundColor:'lightgray'}}
data={[{key: 'a'},{key: 'b'}]}
renderItem={({item}) =>
<View style={styles.item}>
<View style ={styles.pink}></View>
</View>
}
/>
</View>
);
}
}
const styles = StyleSheet.create({
item:{
width:width,
height:150,
alignItems:'center'
},
pink: {
flex:1,
backgroundColor: "#A37E93",
maxHeight:150,
aspectRatio:3/2,
borderWidth:1,
}
});
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"}}>