Get the height of SafeAreaView from within BottomTabBar - react-native

I am attempting to use react-native-keyboard-spacer in conjunction with react-navigation.
I am currently setting the topSpacing of the keyboard spacer to be -49 which is the height of the tab bar from react-navigation, but the tab bar is within a SafeAreaView which magically adds padding to move content into an area that doesn't interfere with native UI.
This means that when viewing the app on an iPhone X, or other similar devices, the tab bar becomes taller than 50.
What would be the best way to get the height of the SafeAreaView?

Here is the list padding from react-navigation SafeAreaView
LandScape Mode
paddingLeft: 44
paddingRight: 44
paddingBottom: 24
paddingTop: 0
Portrait Mode
paddingLeft: 0
paddingRight: 0
paddingBottom:34
paddingTop:44 // ... Including Status bar height

Another option with react-native-safe-area-context (https://github.com/th3rdwave/react-native-safe-area-context):
import { useSafeAreaInsets } from 'react-native-safe-area-context';
...
const insets = useSafeAreaInsets();
Then you can get the bottom safe area height from safeAreaInsets.bottom.

You can use the react-native-safe-area. it provides function to Get safe area inset top, bottom, left, right.
import SafeArea, { type SafeAreaInsets } from 'react-native-safe-area'
//Retrieve safe area insets for root view
SafeArea.getSafeAreaInsetsForRootView()
.then((result) => {
console.log(result)
// { safeAreaInsets: { top: 44, left: 0, bottom: 34, right: 0 } }
})

Below is not supported anymore, for update check here https://github.com/th3rdwave/react-native-safe-area-context
npm install react-native-safe-area-view
import { getInset } from 'react-native-safe-area-view';
const bottomPadding = getInset('bottom', false); //2nd param islandscape
//outputs bottom safe area height

Related

React navigation bottom tab height iphone X and others (with and without tail)

When I set the height of bottom tab style and tab style, the height of all device on ios changes. Which means that if the device do not have the tail bar, it will still have the same height as the one with safeareaview. I would like to make like this: if our device do not have the safeareaview, it will not have a white space at the bottom.
Solved,
use useSafeArea,
import { useSafeArea } from 'react-native-safe-area-context'
const insets = useSafeArea();
style: {
height: 55 + insets.bottom
},
tabStyle: {
height: 55
}

How to make the icon of a bottom tab navigator fit inside the tab bar?

I'm using a bottomTabNavigator in my React Native app. I'm using an component as an icon. Is is possible to make it fit inside the tab (with padding) without explicitly defining a size?
If not, is there some constant in which I can get the tab bar height?
This is what I'm getting:
and this is my tabBarIcon code:
/**
*
*/
import React from 'react';
import {
Image,
Text,
StyleSheet,
} from 'react-native';
export default class TabMenuIcon extends React.Component {
static SCREENS = {
SOCIAL: "s",
CALCULATION: "c",
CONFIGURE: "d"
};
render() {
const { focused, tintColor, size, which } = this.props;
switch(which) {
case TabMenuIcon.SCREENS.SOCIAL:
return <Image source={require('../assets/icons/tabsocial.png')} style={style.img} />
break;
case TabMenuIcon.SCREENS.CALCULATION:
return <Image source={require('../assets/icons/tabcalculations.png')} style={style.img} />
break;
case TabMenuIcon.SCREENS.CONFIGURE:
return <Image source={require('../assets/icons/tabconfigure.png')} style={style.img} />
break;
default:
return <Text>t</Text>
}
}
}
const style = StyleSheet.create({
img: {
padding:6, // Does nothing??
margin: 4, // Does nothing??
}
});
What im saying is dont hardcode the image height, rather you can check for the height of image in your simulator, and suppose you give height and width to be 10.
It fits perfectly suppose. Then to ensure that just giving 10 doesnt break my image in other phones which has different screen resolution you can do ,
height = (10/640) * deviceHeight
width = (10/360) * deviceWidth.
here im assuminb your phone height and width are 640 and 360 respectively.
you can get device height and width by :
import {Dimensions} from 'react-native;
deviceWidth = Dimensions.get('window').width,
deviceHeight= Dimensions.get('window').height
hope it clears

How to handle responsive layout in React Native

I'm using the react-native-dimension library for making my UI responsive as follows:
const{width,height} = Dimensions.get('window');
and in my style.js file :
imageBackgroundLandscape:{
width:height,
height:width
},
imageBackgroundPortrait:{
width:width,
height:height
}
The problem is that when I rotate the screen, the width and height variables have got previous values!
For example in the portrait mode my variables are:
width : 800
height: 1280
and when I rotate the screen my variables are:
width : 800 // previous value
height: 1280 // previous value
In addition, I use the react-native-orientation to determine the mode of the screen.
I want to know how can I change the values of them (width, height) automatically when I rotate the device, or are there any other libraries for this?
Thanks in advance.
I usually handle the height, width confusion with the following code:
//Dimensions.js
import {Dimensions} from 'react-native';
const {height, width} = Dimensions.get('window');
const actualDimensions = {
height: (height<width) ? width : height,
width: (width>height) ? height : width
};
export default actualDimensions;
Instead of requiring the height and width from Dimensions, use the actualDimensions and for managing the orientation gracefully you should give a try to this library as well.
The Dimensions are loaded before the JS bundle gets loaded into the app so it is recommended to fetch the height, width dynamically for every render
You can read this here
I usually used Flexbox to arrange the layout for my components. It helps them to be responsive. Maybe you could give a try too.
Layout with Flexbox
You can use these steps to make your UI responsive.
1: use percentage whenever it's possible
2: use the power of flexbox to make your UI grow and shrink
3: use Dimension API
Actually, you do right but half of the task. you got the width and height from Dimensions and it is right, but how react-native understand your orientation changes?
First, your code should understand the change of orientation, then you set a call-back function to change the state of your application for implementing new width and height.
Awfully, I don't know the react-native can understand a change of orientation with its built-in functions or not. So I'm using this library to understand orientation changes and then I use setState to re-render the codes.
Absolutely, I put the width and height inside state of the component.
If you wanna lock the orientation change, use this library.
Firstly:
You are facing that issue is because you forgot to call const{width,height}
= Dimensions.get('window'); again when the orientation has changed.
In order to get the latest value of width and height after the orientation change you would have to call the Dimensions.get('window') function again and get width and height from it's output.
Secondly:
Instead of using multiple libraries, you can just use one library(react-native-styleman), that lets you handle this type of stuff very easily:
Here is how the code would look like using react-native-styleman.
import { withStyles } from 'react-native-styleman';
const styles = () => ({
container: {
// your common styles here for container node.
flex: 1,
// lets write a media query to change background color automatically based on the device's orientation
'#media': [
{
orientation: 'landscape', // for landscape
styles: { // apply following styles
// these styles would be applied when the device is in landscape
// mode.
backgroundColor: 'green'
//.... more landscape related styles here...
}
},
{
orientation: 'portrait', // for portrait
styles: { // apply folllowing styles
// these styles would be applied when the device is in portrait
// mode.
backgroundColor: 'red'
//.... more protrait related styles here...
}
}
]
}
});
let MainComponent = ({ styles })=>(
<View style={styles.container}>
<Text> Hello World </Text>
</View>
);
// now, lets wire up things together.
MainComponent = withStyles(styles)(MainComponent);
export {
MainComponent
};
I am using react-native-responsive-screen. it is working also with orientation change
USAGE
import {
widthPercentageToDP as wp,
heightPercentageToDP as hp,
listenOrientationChange as lor,
removeOrientationListener as rol
} from 'react-native-responsive-screen';
class Login extends Component {
componentDidMount() {
lor(this);
}
componentWillUnmount() {
rol();
}
render() {
const styles = StyleSheet.create({
container: { flex: 1 },
textWrapper: {
height: hp('70%'),
width: wp('80%')
},
myText: { fontSize: hp('5%') }
});
return (
<View style={styles.container}>
<View style={styles.textWrapper}>
<Text style={styles.myText}>Login</Text>
</View>
</View>
);
}
}
export default Login;

How do I make react native icon sizes flexible?

I'm building a ReactNative iOS/Android app using Expo, and I want to use vector icons for some of my artwork. The issue is the artwork in question needs to scale with the view, I don't want it too small on some devices or too large on another.
With an image, in theory, I could use style = { { width:'100%', aspectRatio: 1 } } to force things to behave. (In theory I say, because it doesn't work consistently)
Is there anything similar for vector icons? Right now I'm just picking a size number that more-or-less works, but I don't want it to stop working on a given size, and it just seems that I'm repeating the mistake of using fixed widths that broke some other screens until I fixed it.
You can use 'Dimensions':
Import Dimensions From react native and then use it to set the size of your image
import {Dimensions} from 'react-native'
const SCREEN_WIDTH = Dimensions.get("window").width;
const logo = require("logo.png");
in render:
then you set the image style:
const styles = StyleSheet.create({
logo: {
height: SCREEN_WIDTH * 0.65,
width: SCREEN_WIDTH * 0.65,
marginLeft: SCREEN_WIDTH * 0.2
}
})

React Native how to do min/max widths

I want to style a component in my interface. The component must have a width of at least 200, but I want to let it grow with screen width to up to 600. But, sometimes people use tablets or huge phones. And I don't want the component to be able to grow with the screen forever. I want it to have a maximum width of 600.
And I know maxWidth is a thing that is, at least for now, not a part of the flexbox implementation in React Native... so, is there a reasonable way to do this today?
You can use the maxWidth, maxHeight, minWidth, minHeight layout properties supported by React Native.
Document here React Native layout props.
Example:
StyleSheet.create({
container: {
maxWidth: '80%', // <-- Max width is 80%
minHeight: 20, // <-- Min height is 20
},
});
There is no such thing as "maxWidth" in React Native. You may want to style your component at run-time. Try playing with Dimensions. You can get screen width and screen height of the device and adjust width of your component accordingly.
You can define two different style objects.
For full-width component on a device having width less than 600.
componentStyle_1: {
flex: 1
}
For 600 width on a device having width greater than 600
componentStyle_2: {
width: 600
}
You can check the device width runtime.
var {height, width} = Dimensions.get('window');
if(width>600){
//load componentStyle_1
}
else{
//load componentStyle_2
}
Best way to get accurate results is to play with your code. Good luck!
Refer: https://facebook.github.io/react-native/docs/dimensions.html#content
Simple. Just use maxWidth in your styles.
In a practical manner, this is how you would use it:
import { StyleSheet, Text, View, Dimensions, (+ anything else you need such as Platform to target specific device widths } from "react-native";
// plus whatever other imports you need for your project...
In a class component, you would create a state called whatever, let's say deviceWidth. Then inside the component you would use:
constructor(props) {
super(props);
this.state = {
deviceWidth: 375, // Put in any default size here or just "null"
// plus any other state keys you need in your project
}
componentDidMount() {
const currentWidth = Dimensions.get("screen").width;
this.setState({deviceWidth: currentWidth});
}
In a functional component you would import:
import React, { useEffect, useState } from "react";
Then inside your functional component you would add in:
const [currentWidth, setCurrentWidth] = useState(null //or add in a default width);
useEffect(() => {
const currentWidth = Dimensions.get("screen").width;
setCurrentWidth({deviceWidth: currentWidth});
}, []);
You could also use:
const deviceDisplay = Dimensions.get("window");
const deviceHeight = deviceDisplay.height;
const deviceWidth = deviceDisplay.width;
..if you wanted to find the height as well. On Android, "window" gets you the full screen height including the upper bar while "screen" gets you height without upper bar. Window and screen on iOS are the same.
Then using inline styles so that you have access to the state, set the width & maxWidth:
<View style={[styles.wrapper, { width: this.state.deviceWidth, maxWidth: 400, // or whatever you want here. } ]} >
Any width settings in a wrapper style found in your StyleSheet object will be over-ridden by the inline style, just like in CSS.
Alternatively if you don't have any other styles declared in your StyleSheet object, just use:
<View style={{ width: this.state.deviceWidth, maxWidth: 400 }} >
Or in a functional component, that would be:
<View style={{ width: deviceWidth, maxWidth: 400 }} >