react native styling component - react-native

I am trying to style a component but cant figure out how to do a couple of things.
1) I want to apply a background color to 100% of my component
return (
<TouchableWithoutFeedback
style={styles.touchable}
onPress={() =>
this.props.navigation.navigate('Quotes', { name: this.props.name })}
>
<View style={styles.viewStyle}>
<Image
source={this.props.image}
key={this.props.image}
style={styles.imageStyle}
/>
<Text style={styles.textStyle}> {this.props.name} </Text>
</View>
</TouchableWithoutFeedback>
);
}
}
const styles = {
imageStyle: {
height: 100,
width: 100
},
touchable: {
width: '100%',
backgroundColor: 'black'
},
viewStyle: {
height:100,
flexDirection: 'row',
alignItems: 'center',
justifyContent: 'center',
width: '100%',
backgroundColor: 'black'
},
textStyle: {
marginLeft: 20,
width: 120,
fontWeight: 'bold',
fontSize: 15
}
}
I tried to apply the background color to touchable tag a view tag but none of this work.
Moreover Id like to position my image at the top left of the component using justifyContent: flex-start. But my elements inside the view tag keeps staying centered.
How can I achieve these goals ?
The parent component is :
render() {
const {listStyle} = styles
return (
<ScrollView style={listStyle}>
{this.renderCharacters(this.props.matches)}
</ScrollView>
);
}
}
const styles = {
listStyle: {
width: '100%',
height: '100%'
}
}

Related

React Navigation (native): Overflow visible not working on custom header

I'm implementing a custom header for #react-navigation/native-stack. Using React Navigation v6.
One of the elements within the custom header has a native shadow on iOS added (via the style prop). The shadow is a tad bigger than the header and unfortunately, I can't get it to display beyond the boundaries of the header. Of course, I've tried using overflow: visible on basically every component in the tree, but no success. The shadow is clipped off:
Here's my custom header:
function CustomHeader(props: NativeStackHeaderProps) {
const { options, route, navigation } = props;
const insets = useSafeAreaInsets();
const headerHeight = Helpers.getHeaderHeight(insets);
return (
<View style={{
height: headerHeight,
paddingTop: insets.top,
width: '100%',
backgroundColor: Colors.white,
display: 'flex',
flexDirection: 'row',
alignItems: 'center',
justifyContent: 'space-between',
paddingLeft: 20,
paddingRight: 20,
overflow: 'visible',
}}
>
<View style={{
flex: 1, display: 'flex', alignItems: 'flex-start',
}}
>
{ options.headerLeft ? options.headerLeft({ canGoBack: false }) : (
<TouchableOpacity
onPress={() => route.name === 'Home'
? null
: navigation.reset({ index: 0, routes: [{ name: 'Home' }] })}
>
<Image
style={{ width: Sizing.logo, height: Sizing.logo }}
source={Logo}
/>
</TouchableOpacity>
)}
</View>
<Text style={{
textAlign: 'center', color: Colors.purple,
}}
>
{(options.title || route.name).toUpperCase()}
</Text>
<View style={{
flex: 1, display: 'flex', alignItems: 'flex-end', overflow: 'visible',
}}
>
{ options.headerRight ? options.headerRight({ canGoBack: false }) : null}
</View>
</View>
);
}
The button on the right with the shadow is passed in through the headerRight option and contains this shadow style:
nativeShadow: {
shadowColor: Colors.gray,
shadowOffset: { width: 0, height: 8 },
shadowRadius: Colors.shadows.gray.distance,
shadowOpacity: 0.5,
},
Any idea what I could try next? I don't want to increase the headers' height since this would break the layout elsewhere.
I had a similar problem with the menu. I think i was taking another way and maybe you should try it.
Be sure that all the parent elements has at least the same height than the navmenu's height.
import React, { Component } from 'react';
import { TouchableOpacity, StyleSheet, Image, View, Text } from 'react-native';
const styles = StyleSheet.create({
menuParent: {
marginLeft: 30,
justifyContent: "flex-start",
alignItems: "flex-end",
flex: 1,
height: 250
},
btnContainer: {
width: 40,
height: 40,
elevation: 50,
zIndex: 50,
marginTop: 5
},
image: {
width: 40,
height: 40,
},
menuContainer: {
position: "absolute",
top: 5,
left: -5,
right: -5,
padding: 20,
borderRadius: 10,
elevation: 10,
zIndex: 10,
flex: 1,
height: 230,
backgroundColor: "#fff",
}
});
export default class DefaultHeaderMenu extends Component {
state = {
menuVisible: false
};
constructor(props) {
super(props);
}
render() {
return (
<View style={ styles.menuParent }>
{this.state.menuVisible ? <View style={ styles.menuContainer }></View> : null }
<TouchableOpacity
style={ styles.btnContainer }
onPress={ () => this.setState({ menuVisible: !this.state.menuVisible }) }
>
<Image
source={ require('#/assets/img/menu.png') }
style={ styles.image }
/>
</TouchableOpacity>
</View>
);
}
}
This is the component i used and the passed it to nav as headerRight element.
In my case, the problem was that height: 250 was missing in menuParent.
I hope it helps you and good luck
I had a problem like this once and fixed it by using 'zIndex'. Try setting it as the* max index in your project. Hope it helps

React Native Button onPressIn animation request

I want to achieve an animation each time a user taps on a button this shrinks in a smaller button.
GIF HERE
For this use TouchableHighlight component from react-native. It has onPressIn and onPressOut on which you can change buttons width and height.
e.g.
export const TouchableHighlightExample = () => {
const [BtnSize, setBtnSize ] = useState({ height: 40, width: "100%" });
const zoomIn=()=>{
setBtnSize({ height: 35, width: "90%",marginHorizontal:"5%" })
}
const zoomOut=()=>{
setBtnSize({ height: 40, width: "100%" })
}
return (
<View style={styles.container}>
<TouchableHighlight underlayColor="#ffffff00" onPressIn={zoomIn} onPressOut={zoomOut}>
<View style={[styles.button,BtnSize]}>
<Text style={{color: "white"}}>Touch Here</Text>
</View>
</TouchableHighlight>
</View>
);
}
const styles = StyleSheet.create({
container: {
flex: 1,
justifyContent: 'center',
paddingHorizontal: 10,
},
button: {
alignItems: 'center',
backgroundColor: 'red',
padding: 10,
borderRadius:40
},
});

Elements inside ScrollView dont scroll React native

I have trouble understanding how ScrollView works in React Native. In my view, I have a scrollview that is wrapped in a containerview with containerStyle that has a flex:1. However the elements inside my view dont scroll..
render() {
const {containerStyle, eventsWrapperStyle, footerStyle} = styles
return (
<View style={containerStyle}>
<Header/>
<ScrollView style={eventsWrapperStyle}>
{this.renderEvents()}
{this.renderMonthlyStats()}
</ScrollView>
<Footer>
<View style={styles.footerButtonsWrapper}>
<Button customStyle={styles.footerButtonStyle} onPress = {() => this.props.resetAppInfo()}>NEW</Button>
<Button customStyle={styles.footerButtonStyle} onPress={() => this.props.logoutUser()}>SIGN OUT</Button>
</View>
</Footer>
</View>
)
}
const styles = {
monthlyStatsWrapper: {
margin: 10,
flexDirection: 'column'
},
monthlyStatsLine: {
width: '85%',
alignItems: 'center',
marginTop: 10,
flexDirection: 'row',
justifyContent: 'space-between'
},
containerStyle: {
flex: 1,
flexDirection: 'column',
alignItems: 'center',
},
footerButtonsWrapper: {
flex: 1,
flexDirection: 'row',
alignItems: 'center',
justifyContent: 'center'
},
footerButtonStyle: {
width: 170
},
eventsWrapperStyle: {
marginTop: 50,
padding: 30,
flex: 1,
paddingBottom: 100,
}
};
Could you help me understand how scrollView works and make my elements inside it scroll ?
Here's the code for the Footer element which is absolutely positioned (might be part of the problem ?)
class Footer extends Component {
render(){
const { footerStyle } = styles;
return (
<View style={[footerStyle, this.props.customStyle]}>
{this.props.children}
</ View>
);
}
};
const styles = {
footerStyle: {
position: 'absolute',
width: '100%',
bottom: 0,
height: 130,
backgroundColor: '#FCFCFC'
}
};

React Native Navigator Not Working

I've been struggling with Navigator in React Native Web for a good 2 days now and can't figure out what the problem is. It is worth noting that before attempting to use the Navigator, everything was working fine, and this code is running on a browser. I have the following code below and keep getting the error message:
"bundle.js:784 Warning: React.createElement: type should not be null, undefined, boolean, or number. It should be a string (for DOM elements) or a ReactClass (for composite components). Check the render method of Home."
Followed by:
"bundle.js:640 Uncaught Invariant Violation: Element type is invalid: expected a string (for built-in components) or a class/function (for composite components) but got: undefined. Check the render method of Home."
Basically, I have a component called "Home" and I am trying to renderScene using the Navigator fairly deeply nested in this component but it isn't working. I have used this same Navigator code on another app and it worked, minus a few changes in the props passed. Any help would be greatly appreciated!
const React = require('react-native-web')
const {
Text,
View,
StyleSheet,
Image,
Navigator,
TouchableHighlight,
Component
} = React;
var Home = React.createClass({
renderScene(route, navigator) {
if(route.name == 'Baseball') {
return <Baseball navigator={navigator} {...route.passProps} />
}
if(route.name == 'Football') {
return <Football navigator={navigator} {...route.passProps} />
}
},
render() {
return (
<View>
<View>
<Image
style={styles.homeImage}
source={require('./img/baseball.png')}>
<View style={styles.tagLineWrapper}>
<Text style={styles.tagLine}>
Real Sports.
</Text>
<Text style={styles.tagLine}>
Real Skill.
</Text>
<Text style={styles.tagLine}>
Real Prizes.
</Text>
</View>
</Image>
</View>
<View style = {styles.appStoreBar}>
<Text style={styles.darkText}>
Available Now!
</Text>
<View style={styles.appStoreButton}>
<Image
style={styles.button}
source={require('./img/app-store-button-yellow.png')}
/>
</View>
</View>
<Text style = {styles.instructionsHeader}>
How Pick a Play Works
</Text>
<View style = {styles.doubleIphoneWrapper}>
<View style = {styles.singleIphoneWrapper}>
<Text style = {styles.instructionsSubHeaderText}>
1. Pick a Contest
</Text>
<View style={styles.instructionsWrapper}>
<Text style={styles.instructions}>
Pick 5, 6, or 7 correctly and win the amount shown on the right.
</Text>
</View>
<View style={styles.iphoneAndChevronWrapper}>
<Image
style={styles.chevronIcons}
source={require('./img/chevron-left.png')}
/>
<View style={styles.iphoneAndScreenWrapper}>
<Image
style={styles.iphone}
source={require('./img/iphone5-vertical.png')} >
<Navigator
initialRoute={{name: 'Baseball'}}
renderScene={this.renderScene} />
</Image>
</View>
<Image
style={styles.chevronIcons}
source={require('./img/chevron-right.png')}
/>
</View>
</View>
<View style = {styles.singleIphoneWrapper}>
<Text style = {styles.instructionsSubHeaderText}>
1. Pick a Game
</Text>
<View style={styles.instructionsWrapper}>
<Text style={styles.instructions}>
Make sure it’s a game you are available to watch in real time.
</Text>
</View>
<View style={styles.iphoneAndChevronWrapper}>
<Image
style={styles.chevronIcons}
source={require('./img/chevron-left.png')}
/>
<Image
style={styles.iphone}
source={require('./img/iphone5-vertical.png')}>
</Image>
<Image
style={styles.chevronIcons}
source={require('./img/chevron-right.png')}
/>
</View>
</View>
</View>
</View>
)
}
})
var Baseball = React.createClass({
_navigate(name) {
this.props.navigator.push({
name: 'Football',
passProps: {
name: name
}
})
},
render() {
return (
<View style={[styles.screenView, {backgroundColor: 'blue'}]}>
</View>
)
}
})
var Football = React.createClass({
_navigate(name) {
this.props.navigator.push({
name: 'Baseball',
passProps: {
name: name
}
})
},
render() {
return (
<View style={[styles.screenView, {backgroundColor: 'green'}]}>
</View>
)
}
})
const styles = StyleSheet.create({
homeText: {
color: '#1C1C1C',
fontFamily: '"Helvetica Neue", Helvetica, Arial, sans-serif'
},
homeImage: {
maxHeight: 350,
flex: 0
},
tagLineWrapper: {
alignSelf: 'flex-end',
marginRight: 200,
marginTop: 220
},
tagLine: {
fontSize: 20,
fontStyle: 'italic',
color: 'white',
alignSelf: 'flex-start',
marginTop: 10,
fontFamily: '"Helvetica Neue", Helvetica, Arial, sans-serif'
},
instructionsHeader: {
fontSize: 27,
fontWeight: 'bold',
marginTop: 40,
color: '#1C1C1C',
alignSelf: 'center'
},
doubleIphoneWrapper: {
flexDirection: 'row',
justifyContent: 'center'
},
singleIphoneWrapper: {
flexDirection: 'column',
justifyContent: 'center',
alignItems: 'center',
margin: 40
},
instructionsSubHeaderText: {
fontSize: 18,
color: '#1C1C1C',
marginTop: 60,
alignSelf: 'center'
},
instructionsWrapper: {
width: 194,
height: 64,
alignSelf: 'center'
},
instructions: {
fontSize: 13,
padding: 20,
textAlign: "center"
},
appStoreBar: {
alignSelf: 'stretch',
flexDirection: 'row',
justifyContent: 'center',
alignItems: 'center',
padding: 30,
backgroundColor: '#ededed'
},
darkText: {
fontSize: 24,
color: '#1C1C1C',
marginRight: 10
},
appStoreButton: {
width: 200,
marginLeft: 10
},
iphone: {
width: 300,
margin: 30
},
chevronIcons: {
height: 30,
alignSelf: 'center',
margin: 0
},
iphoneAndChevronWrapper: {
flexDirection: 'row',
justifyContent: 'center',
alignItems: 'center'
},
screenView: {
height: 338,
width: 192,
alignSelf: 'center',
marginTop: 100,
},
iphoneAndScreenWrapper: {
justifyContent: 'center',
alignItems: 'center',
}
})
module.exports = Home;
This might be late, but you should know that React Native Navigator does not work with React Native Web. But I guess there are some alternative solutions though. I don't remember at the top of my head at the moment.

In React Native, how do I put a view on top of another view, with part of it lying outside the bounds of the view behind?

I'm trying to make a layout as per below with React Native.
How do I specify the position of B relative to A?
With iOS Interface Builder and autoconstraints, this can very explicitly be done and is a breeze. It's not so obvious how one might achieve this with React Native.
Add the following style to the "floating" view:
position: 'absolute'
You may also need to add a top and left value for positioning.
The above solutions were not working for me. I solved it by creating a View with the same background colour as the parent and added negative margin to move the image upwards.
<ScrollView style={{ backgroundColor: 'blue' }}>
<View
style={{
width: '95%',
paddingLeft: '5%',
marginTop: 80,
height: 800,
}}>
<View style={{ backgroundColor: 'white' }}>
<Thumbnail square large source={{uri: uri}} style={{ marginTop: -30 }}/>
<Text>Some Text</Text>
</View>
</View>
</ScrollView>
and I got the following result.
You can use zIndex for placing a view on top of another. It works like the CSS z-index property - components with a larger zIndex will render on top.
You can refer: Layout Props
Snippet:
<ScrollView>
<StatusBar backgroundColor="black" barStyle="light-content" />
<Image style={styles.headerImage} source={{ uri: "http://www.artwallpaperhi.com/thumbnails/detail/20140814/cityscapes%20buildings%20hong%20kong_www.artwallpaperhi.com_18.jpg" }}>
<View style={styles.back}>
<TouchableOpacity>
<Icons name="arrow-back" size={25} color="#ffffff" />
</TouchableOpacity>
</View>
<Image style={styles.subHeaderImage} borderRadius={55} source={{ uri: "https://upload.wikimedia.org/wikipedia/commons/thumb/1/14/Albert_Einstein_1947.jpg/220px-Albert_Einstein_1947.jpg" }} />
</Image>
const styles = StyleSheet.create({
container: {
flex: 1,
backgroundColor: "white"
},
headerImage: {
height: height(150),
width: deviceWidth
},
subHeaderImage: {
height: 110,
width: 110,
marginTop: height(35),
marginLeft: width(25),
borderColor: "white",
borderWidth: 2,
zIndex: 5
},
You can use this OverlayContainer. The trick is to use absolute with 100% size. Check below an example:
// #flow
import React from 'react'
import { View, StyleSheet } from 'react-native'
type Props = {
behind: React.Component,
front: React.Component,
under: React.Component
}
// Show something on top of other
export default class OverlayContainer extends React.Component<Props> {
render() {
const { behind, front, under } = this.props
return (
<View style={styles.container}>
<View style={styles.center}>
<View style={styles.behind}>
{behind}
</View>
{front}
</View>
{under}
</View>
)
}
}
const styles = StyleSheet.create({
container: {
flex: 1,
alignItems: 'center',
height: '100%',
justifyContent: 'center',
},
center: {
width: '100%',
height: '100%',
alignItems: 'center',
justifyContent: 'center',
},
behind: {
alignItems: 'center',
justifyContent: 'center',
position: 'absolute',
left: 0,
top: 0,
width: '100%',
height: '100%'
}
})
import React, {Component} from 'react';
import {StyleSheet, View} from 'react-native';
export default class App extends Component {
render() {
return (
<View>// you need to wrap the two Views an another View
<View style={styles.box1}></View>
<View style={styles.box2}></View>
</View>
);
}
}
const styles = StyleSheet.create({
box1:{
height:100,
width:100,
backgroundColor:'red'
},
box2:{
height:100,
width:100,
backgroundColor:'green',
position: 'absolute',
top:10,
left:30
},
});
You can use react-native-view-overflow plugin for placing a view on top of another. It works like the CSS z-index property.
import ViewOverflow from 'react-native-view-overflow';
<ViewOverflow />
<View style={[styles2.cardBox, { marginTop: 50 }]}>
<View style={[styles2.cardItem]} >
<Text style={styles2.cardHeader}>userList</Text>
</View>
<View style={[styles2.cardContent]}>
<Text style={styles2.text}>overflow: "visible"</Text>
</View>
<View style={[styles2.cardItemFooter]} >
<Text style={styles2.cardTextFooter}>...</Text>
</View>
</View>
</ViewOverflow>
const styles2 = StyleSheet.create({
cardBox: {
borderLeftWidth: 0,
borderTopWidth: 0,
backgroundColor: "transparent",
borderWidth: 1,
borderColor: "#d0d0d0",
width: '94%',
alignSelf: 'center',
height: 200,
position: "relative",
borderRadius: 15,
overflow: "visible" // doesn't do anything
},
cardContent: {
textAlign: "right",
backgroundColor: "transparent",
marginTop: 15,
alignSelf: 'flex-end',
padding: 5,
},
cardHeader: {
color: '#fff',
fontFamily: 'Vazir',
fontSize: 12
},
cardItem: {
backgroundColor: "#3c4252",
borderRadius: 3,
position: "absolute",
top: -10,
right: -5,
width: 50,
height: 20,
paddingRight: 5,
},
})
The easiest way to achieve this is with a negative margin.
const deviceWidth = RN.Dimensions.get('window').width
a: {
alignItems: 'center',
backgroundColor: 'blue',
width: deviceWidth,
},
b: {
marginTop: -16,
marginStart: 20,
},
You can use elevation property for Android if you don't mind the shadow.
{
elevation:1
}
Try this:
style = {{position: 'absolute', bottom: 20, left: 20, elevation: 100}}
Based on the example above i've created a component which stacks all childeren on top of each other. You could even nest OverlayContainers inside OverlayContainers.
Usage:
<OverlayContainer>
<View style={{backgroundColor:'red', width:150, height: 150}}></View>
<View style={{backgroundColor:'yellow', width:50, height: 50}}></View>
<Text>Just some text</Text>
</OverlayContainer>
Output:
import React, { FC, PropsWithChildren } from 'react'
import { StyleSheet, View } from 'react-native'
export const OverlayContainer: FC<PropsWithChildren<unknown>> = (props) => {
return (
<View style={styles.container}>
{props.children.map((child, index) => (
<View style={styles.child} key={index}>
{child}
</View>
))}
</View>
);
}
const styles = StyleSheet.create({
container: {
flex: 1,
height: '100%',
},
child: {
position: 'absolute',
left: 0,
top: 0,
width: '100%',
height: '100%'
}
})
<SafeAreaView style={{ flex: 1 }} >
<View style={{ height: Dimensions.get('window').height / 2, backgroundColor: 'blue', justifyContent: 'center' }}>
<Text style={{ fontSize: 25, alignSelf: 'center' }} >A</Text>
<View style={{ justifyContent: 'center', height: 100, width: 100, backgroundColor: 'yellow', position: 'absolute', left: 20, top: Dimensions.get('window').height / 2 - 70 }}>
<Text style={{ fontSize: 22, alignSelf: 'center' }} >B</Text>
</View>
</View>
</SafeAreaView>