Conditional Styling in React Native - javascript

I have this ImageBackground tag in my React-Native App.
const{height,width} = Dimensions.get('window);
const navHeight = ExtraDimensions.get('SOFT_MENU_BAR_HEIGHT');
render(){
return(
<ImageBackground source={Images.bg} style={{width=width+48,height=height}}>
//content
</ImageBackground>
);
}
The number 48 is the height of the default Android navigation bar (the one contains BACK button). The navHeight is to detect the height of navigation bar on the device (refer here:https://github.com/Sunhat/react-native-extra-dimensions-android).
Since there are now devices with no navigation bar, i want to make a conditional styling in the ImageBackground style to take style={styles.bg1} when there is a value of navHeight and take style={styles.bg2} when there is no navHeight value.
May i know where and how should i implement the styling? thanks
My current wrong way of doing it is
<ImageBackground source={Images.bg} style={navHeight=0 ? styles.bg1 : styles.bg2}>

There is a syntatical error, for comparison you have to use ==.
Try this,
<ImageBackground source={Images.bg} style={ (navHeight==0) ? styles.bg1 : styles.bg2}>
Moreover, i would recommend you using Image tag and append a child component to it by using position="absolute". Because some styling props like borderRadius don't work in the case of ImageBackground tag.
I hope this helps you !

Related

How can you ensure flex shrink in react-native (and how can you debug react-native styles in general)?

I'm running a RN app using native-base for styling. I have four elements on my homepage: a header, a tab view from vreact-native-tab-view that contains a ScrollView that takes up about 70% of the viewport, and two smaller 100% width elements at the bottom.
However, the scrollview fills up more than 100% of the viewport and the two smaller elements get pushed to the bottom.
I looked in my element inspector and can apply a flexShrink to some of the many divs, but I'm not sure which one that is in my code because it's div hell when you use react-native. React devtools also has the same problem, except it's View hell.
So, two questions:
How can I ensure the scroll container doesn't fill up more than it should on the page?
How can I effectively debug react native when both chrome and react dev tools are a mess?
For reference, here's how I've styled so far:
Home.tsx:
<View flex={1}> // applied a flex for the entire homepage
<TabView
navigationState={{ index, routes }}
renderScene={renderScene}
renderTabBar={renderTabBar}
onIndexChange={setIndex}
initialLayout={{ width: layout.width, height: "100%" }}
/>
<View width="100%">
<Center width="100%">
<StrengthSlider />
</Center>
<AdMobBanner
...props
/>
</View>
</View>
Teas.tsx:
<View flex={1} bg="white">
<ScrollCards teas={blackTeas} />
</View>
ScrollCards.tsx:
<ScrollView>
<Center>
{teas.length > 0 &&
teas.map((teaObj) => (
<TeaCard id={teaObj.id} teaData={teaObj.data} key={teaObj.id} />
))}
</Center>
</ScrollView>
EDIT:
Code Sandbox link: https://codesandbox.io/s/gracious-sammet-l4tqz?file=/src/App.js&resolutionWidth=402&resolutionHeight=675
Note that the admob footer remains underneath the cards content. It should be sticky and remain always at the bottom of the screen. I also noticed that when I'm not using the header from the MainStackNavigator the footer works as intended - i.e. it remains sticky at the bottom - but I don't see why using the header (AppBar) component should interfere with my footer.
The proper solution to get the result you want is to add a flexBasis to the TabView like:
<TabView
style={{ flexBasis: 0 }}
// rest of the code
/> ​
Why?
The TabView has a default style of flex: 1, overflow: 'hidden' (see source code) causing it to expanded to the size of its biggest child. The flexBasis prevents this and makes sure the tabview get the correct height.
Resource: This is a nice article about flexBasis vs width/height: https://mastery.games/post/the-difference-between-width-and-flex-basis/
Debugging styling in React-Native doesn't have the best developer experience. There are some things you can use to help you with debugging styling:
RN inspector: As Berci mentioned, React native has a dev menu where you can select "show inspector" that kinda acts like "inspect element" in a browser. It is a good tool to debug elements you can see, it also helps with debugging input/tab events.
Color: Most often I just use old fashioned colored borders & background to get a clear view of where elements are & their size/overlaps.
Comments & Simplify: Feel free to comment out components you're not interested in and replace complex components/views like ScrollCards with just a simple colored view. This can help prevent multiple behaviours from influencing the thing you're trying to debug
Browser inspect & React devtools: If you happen to run your RN app in the browser, then getting familiar with those tools will help you loads. Just keep in mind that React & React-Native isn't the same.
When you debug visuals, the best way is start at the top layer and work you way down. Color the elements & feel free to comment out elements to get you a clearer view of the problem. Keep digging down until you find the problem, don't be afraid to look into the source code of the packages you use, it often helps clarify (unexpected) behaviours.
You could try to replace
<View flex={1}> // applied a flex for the entire homepage
in Home.tsx with
<View flex="1 1 0">
Working example here (is your code with that line modified).
As for debugging I can only suggest what is already suggested on react native Debugging page. Have you tried React Developer Tools yet? In chrome you can also add it as an extension from this link.
I am not sure if there is any difference between chrome extension and the npm package but the extension was enough for me at least (for now).
The only problem is that I also struggled debugging on codesandbox since the extension is definitely not working on javascript online editors (but probably the npm package doesn't either for this specific case)
Try this - https://snack.expo.dev/fL0OgQ9uS
import React from 'react';
import { View, Image, StyleSheet,ScrollView,Text } from 'react-native';
const styles = StyleSheet.create({
container: {
paddingTop: 50,
flex:1,
backgroundColor:'aqua',
},
tinyLogo: {
width: 200,
height: 200,
},
header:{
backgroundColor:'green',
paddingBottom:20,
},
footer:{
backgroundColor:'green',
paddingTop:20,
}
});
const DisplayAnImage = () => {
return (
<View style={styles.container}>
<View style={styles.header}><Text>header</Text></View>
<ScrollView>
<Image
style={styles.tinyLogo}
source={require('#expo/snack-static/react-native-logo.png')}
/>
<Image
style={styles.tinyLogo}
source={require('#expo/snack-static/react-native-logo.png')}
/>
<Image
style={styles.tinyLogo}
source={require('#expo/snack-static/react-native-logo.png')}
/>
<Image
style={styles.tinyLogo}
source={require('#expo/snack-static/react-native-logo.png')}
/>
<Image
style={styles.tinyLogo}
source={require('#expo/snack-static/react-native-logo.png')}
/>
<Image
style={styles.tinyLogo}
source={require('#expo/snack-static/react-native-logo.png')}
/>
<Image
style={styles.tinyLogo}
source={require('#expo/snack-static/react-native-logo.png')}
/>
</ScrollView>
<View style={styles.footer}><Text>footer</Text></View>
</View>
);
}
export default DisplayAnImage;

HeaderRight Buttons are not clickable (React Native)

I am experiencing an odd bug with the React Native Navigation v5 headerRight Buttons. I currently have a TouchableOpacity set as a headerRight component in the react native navigation screen; however, the onPress event is not being triggered. There seems to be an invisible object in the middle of the header (title area) that has an absolute position, which prevents the onPress event from being registered. I tried playing around with the zIndex and headerMode values; however, the button is still not pressable. I can only press the button when it is placed on the far right of the screen (i.e. marginRight: 0). Any help would be greatly appreciated.
For reference, I am encountering the same issues as the following thread: https://github.com/react-navigation/react-navigation/issues/7052
Example of my Code
<StackNavigator.Navigator headerMode='screen'>
<StackNavigator.Screen
name='Home'
component={HomeScreen}
options={{
headerRight: () => (
<TouchableOpacity
onPress={() => {}}
>
<Text>Button Text</Text>
</TouchableOpacity>
),
}}
/>
</StackNavigator.Navigator>
Updating to the following packages seems to have resolved it for me:
"#react-navigation/stack": "5.9.3",
"#react-navigation/drawer": "5.9.3",
"#react-navigation/native": "5.7.4",
Try to give higher values to zIndex may be 100 or give headerMode: float if that not also not works try updating your packages .

Make ScrollView - Items use a percentage size of the whole screen

My current scrollview items have the problem, that I need to set a fixed height and width for them in order to show up properly on different devices.
Every scrollview item should use 1/6 of the screen height in order to fit for different screen sizes... but how do we achieve this without making the scrollview unscrollable ?
My current attempt...
<ScrollView style={{backgroundColor: 'blue'}} contentContainerStyle={{flexGrow: 1}}>
{ /* Renders the header */}
<Header text={Constants.header} screen="Drills&Games"/>
<BoxView></BoxView>
<BoxView></BoxView>
<BoxView></BoxView>
<BoxView></BoxView>
<BoxView></BoxView>
</ScrollView>
export default class BoxView extends Component{
render(){
return(
<View style={{backgroundColor: 'red', flex: 0.25}}>
</View>
);
}
}
Renders a scrollview with 5 BoxView-Items... The problem here is... the box views do scale correctly, each one uses 0.25 flex, but the list is not scrollable anymore.
So how do we pass a percentage/flex height to the items with keeping the scrollview scrollable ?
On react native I recommend using Dimensions on setting dynamic height.
for getting the 1/6 of the screen I would do is
{ height: Dimensions.get("screen").height * 0.16 }

How can I efficiently render an Image Component in a React Native Header bar?

Overview
I am currently working on a React Native application that uses the React Navigation library. From the React Navigation library, I'm using the navigationOptions property to create a Header component in each of my screens. Each screen uses the exact same properties:
HomeScreen.navigationOptions = {
headerRight: (
<Ionicons
name={"md-menu"}
size={26}
style={{ marginBottom: -5, paddingRight: 15 }}
color={"#ccc"}
/>
),
headerTitle: (
<HeaderLogo/>
)
}
My Logo component is as such:
export default HeaderLogo = () => {
const logo = require("../../../assets/images/logo.png");
return (
<Image
style={{
resizeMode: "contain",
height: 40,
width: 85,
marginLeft: 85
}}
source={logo}
/>
)
}
The problem
The logo renders in the header correctly as expected; however, whenever I switch screens, the logo briefly disappears and reappears in a flash. Its noticeable and does not look good. I want the header to appear static no matter how many times I switch screens. I'm assuming this has something to with the require()method, where its pulling the image everytime. My question is:
How can I efficiently use an Image component in my Header, such that the header appears static?
Add headerMode: 'float' to the navigationOptions of the stack navigator that contains your screens.
From createStackNavigator documentation:
headerMode - Specifies how the header should be rendered:
float - Render a single header that stays at the top and animates as screens are changed. This is a common pattern on iOS.
screen - Each screen has a header attached to it and the header fades in and out together with the screen. This is a common pattern on Android.
none - No header will be rendered.

React Native Scrollview Stop Momentum? (expo)

I am using a ScrollView, and when I scroll and let go, it keeps scrolling because of momentum. I want it to only scroll when the finger is touching the screen, I do not want the momentum. Is this possible, if so, how?
Using decelerationRate prop with value 0 can help.
Based on the document, its value accept string normal | fast and floating number from 0 to 1 orderly from slowest to fastest.
<ScrollView decelerationRate={0}>
</ScrollView>
** I am using RN v0.59 **
Add 2 following properties to ScrollView:
snapToInterval={1}
disableIntervalMomentum={true}
Why not try this (RN 0.55)
<ScrollView
ref={r => (this.scrollView = r)}
onScrollEndDrag={e => {
return this.scrollView.scrollTo({ y: e.nativeEvent.contentOffset.y });
}}>
...
</ScrollView>

Categories

Resources