How do I make react native icon sizes flexible? - react-native

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
}
})

Related

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;

Get the height of SafeAreaView from within BottomTabBar

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

React native navigation newbie: Fullscreen width on a showInAppNotification?

I'm using react-native-navigation to show error notification dropdowns via 'showInAppNotification'.
I've tried to style the dropdown box with:
{
backgroundColor: colorRed,
flex: 1,
alignSelf: 'stretch',
}
I can't get the box to obey that flex call. It stays as the width of the text inside the notification.
That is, what I get is this:
And what I want is this:
(The second is achieved by setting a hard width of 999, but that isn't a satisfactory solution)
So, from my limited understanding of React Native's stylesheet logic, I assumed I had a parent element with a fixed width above the notification. Except I don't. It's called directly (well, unless I'm missing some sort of injected showInAppNotification component) into my Provider HOC, which looks like this:
<Provider store={store}>
<ErrorBoundary>
{children}
</ErrorBoundary>
</Provider>
To confirm the ErrorBoundary was fullscreen width, I threw a backgroundColor: green on the error boundary. It came back as the expected width, like this:
Any thoughts on what could be going on? As mentioned I'm new to react native & it's possible I'm missing something obvious w/regards to flex logic, but I suspect it's a react-native-navigator notification issue I'm hoping others have run into. Any thoughts appreciated.
Instead of giving your width a hard-coded value you can import react native's Dimensions class into your component and use it in order to set the width.
So, your code can look something like this:
import { ...., Dimensions } from 'react-native';
const { width } = Dimensions.get('window');
const styles = {
notification : {
backgroundColor: colorRed,
width,
alignSelf: 'stretch'
}
}

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 }} >

Minimum width/height in React Native

How can I set minimum width or height for React Native component?
In css, I can use min-width/min-height
https://facebook.github.io/react-native/docs/flexbox.html#content
There is no minWidth/minHeight on react-native docs
minHeight, maxHeight, minWidth and maxWidth properties are supported as of react-native version 0.29.0 for iOS and Android.
Here is the maxHeight description from react-native documentation. This description also applies for other min/max style properties.
maxHeight is the maximum height for this component, in
logical pixels.
It works similarly to max-height in CSS, but in React Native you must
use points or percentages. Ems and other units are not supported.
See https://developer.mozilla.org/en-US/docs/Web/CSS/max-height for
more details.
A dummy example:
<View
style={{
minWidth: '20%',
maxWidth: 500,
minHeight: '10%',
maxHeight: 150,
}}
/>
This answer is outdated now, use halilb's answer.
I solved this by using the onLayout prop, its very easy:
Example:
Step 1: I create a prop in our state that will be holding the current height of the image called curImgHeight.
constructor(){
super(props);
this.state={curImgHeight:0}
}
Step 2: Use the prop in any View or Element that supports the onLayout prop.
Here I use it with an Image. Then all we have to do is, change that state property whenever the actual image height is than our minimum height.
render(){
<Image
source={{uri: "https://placehold.it/350x150"}}
resizeMode='cover'
style={[styles.image, {height:(this.state.curImgHeight<=0?null:this.state.curImgHeight)}]}
onLayout={(e)=>{
let {height} = e.nativeEvent.layout;
let minimumImgHeight = 400; //We set the minimum height we want here.
if(height<= minimumImgHeight){ //Whenever the real height of the image is less than the minimum height
this.setState({curImgHeight:minimumImgHeight}); //just change the curImgHeight state property to the minimum height.
}
}}
/>
}
Thats how I solved it for me.
p.s: During my search I found that react-native unofficially supports minHeight and maxHeight but only for iOS and not for Android. I wouldn't dare using them though. The above code works well and gives me control.
I was able to work out the solution for you. Here's a working demo...
https://rnplay.org/apps/vaD1iA
And here are the key parts.
First, you pull in the device dimensions...
var Dimensions = require('Dimensions');
var {
width,
height
} = Dimensions.get('window');
Here's the button component, which uses the device width as the basis for the button's with
const Button = React.createClass({
render(){
return(
<TouchableHighlight>
<Text style={[styles.button,{width: width - 20}]}>
{this.props.children}
</Text>
</TouchableHighlight>
)
}
});
Then, as you can see here, the button width will be the same regardless of label content width.
You can use minHeight or flexBasis - it is similar.
You can do something like that:
_getButtonStyle() {
var style = {height:36,padding:8}
if(this.props.buttonText.length < 4){
style.width = 64
}
return style
}