Skip to content

Commit

Permalink
Merge branch 'development'
Browse files Browse the repository at this point in the history
  • Loading branch information
marudy committed Apr 24, 2018
2 parents c734c6d + 7bcced6 commit 9a8cd6b
Show file tree
Hide file tree
Showing 2 changed files with 152 additions and 13 deletions.
121 changes: 113 additions & 8 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,9 @@

react-native-responsive-screen is a small library that provides 2 simple methods so that React Native developers can code their elements with responsive independent pixel (dp) values. No media queries needed.

It can be easily combined with other CSS libraries for React Native, i.e. [styled components](https://www.styled-components.com/) and [Expo framework](https://expo.io/) as well.
<b>UPDATE:</b> From version <b>1.1</b> onwards, it provides an optional third method for screen orienation detection and automatic rerendering according to new dimensions.

It can be easily combined with other CSS libraries for React Native, i.e. [styled components](https://www.styled-components.com/) and [Expo framework](https://expo.io/) as well. Check out the [Usage](#usage) section below for more details.

Give it a try and make your life simpler!

Expand All @@ -19,17 +21,19 @@ This package provides a way to use percentages - the developer provides percenta
`npm install react-native-responsive-screen --save`

# Usage
```

## 1. How to use with StyleSheet.create() and without orientation change support
```javascript
import React, {Component} from 'react';
import {
StyleSheet,
Text,
View,
} from 'react-native';
import {StyleSheet, Text, View} from 'react-native';
import {widthPercentageToDP, heightPercentageToDP} from 'react-native-responsive-screen';

class Login extends Component {
this.state = {};
constructor(props) {
super(props);

this.state = {};
}

render() {
return (
Expand Down Expand Up @@ -58,6 +62,107 @@ const styles = StyleSheet.create({
export default Login;
```

## 2. How to use with StyleSheet.create() and with orientation change support
In odrer to detect orientation change, there are 2 major differences from the previous case:
* we add a listener function in every screen that supports orientation change (and a remove listener function respectively)
* we move the stylesheet creation inside the render function, so that the styles are recalculated whenever we detect an orientation change (and therefore trigger a rerender).

When using this, make sure to monitor UI performance of your app in a real device on orienation change. Since the styles are calculated every time from scratch inside the render function, make sure it's nor affecting your performance, especially on complicated screens with many UI elements.

```javascript
import React, {Component} from 'react';
import {StyleSheet, Text, View} from 'react-native';
import {
widthPercentageToDP,
heightPercentageToDP,
listenOrientationChange,
removeOrientationListener
} from 'react-native-responsive-screen';

class Login extends Component {
constructor(props) {
super(props);

this.state = {};

listenOrientationChange(this);
}

componentWillUnMount() {
removeOrientationListener();
}

render() {
const styles = StyleSheet.create({
container: {
flex: 1
},
textWrapper: {
height: heightPercentageToDP('70%'), // 70% of height device screen
width: widthPercentageToDP('80%') // 80% of width device screen
},
myText: {
fontSize: heightPercentageToDP('5%') // End result looks like the provided UI mockup
}
});

return (
<View style={styles.container}>
<View style={styles.textWrapper}>
<Text style={styles.myText}>Login</Text>
</View>
</View>
);
}
}

export default Login;
```

## 3. How to use with styled components
Same logic applies as above in case you want to use the package with or without orientation change support. Below se show a sample setup with styled compoments and without orientation change support.

```javascript
import React, {Component} from 'react';
import {widthPercentageToDP, heightPercentageToDP} from 'react-native-responsive-screen';
import styled from 'styled-components/native';

class Login extends Component {
constructor(props) {
super(props);

this.state = {};
}

render() {
return (
<Container>
<TextWrapper>
<Login>Login</Login>
</TextWrapper>
</Container>
);
}
}

const Container = styled.View`
flex: 1;
`;

const TextWrapper = styled.View`
height: heightPercentageToDP('70%'); // 70% of height device screen
width: widthPercentageToDP('80%'); // 80% of width device screen
`;

const Login = styled.Text`
font-size: heightPercentageToDP('5%') // End result looks like the provided UI mockup
`;

export default Login;
```



# How do I know it works for all devices ?

As mentioned in ["How to Develop Responsive UIs with React Native"](https://medium.com/building-with-react-native/how-to-develop-responsive-uis-with-react-native-1x03-a448097c9503) article, this solution is already in production apps and is tested with a set of Android, iOS emulators of different screen specs, in order to verify that we always have the same end result.
Expand Down
44 changes: 39 additions & 5 deletions src/index.js
Original file line number Diff line number Diff line change
@@ -1,14 +1,14 @@
// packages
import { Dimensions, PixelRatio } from 'react-native';

// Retrieve screen's width once
// Retrieve initial screen's width
const screenWidth = Dimensions.get('window').width;

// Retrieve screen's height once
// Retrieve initial screen's height
const screenHeight = Dimensions.get('window').height;

/**
* Converts provided width percentage to independent pixel (dp).
* Converts provided width percentage to independent pixel (dp).
* @param {string} widthPercent The percentage of screen's width that UI element should cover
* along with the percentage symbol (%).
* @return {number} The calculated dp depending on current device's screen width.
Expand All @@ -18,7 +18,7 @@ const widthPercentageToDP = widthPercent => {
const elemWidth = parseFloat(widthPercent);

// Use PixelRatio.roundToNearestPixel method in order to round the layout
// size (dp) to the nearest one that correspons to an integer number of pixels.
// size (dp) to the nearest one that correspons to an integer number of pixels.
return PixelRatio.roundToNearestPixel(screenWidth * elemWidth / 100);
};

Expand All @@ -37,7 +37,41 @@ const heightPercentageToDP = heightPercent => {
return PixelRatio.roundToNearestPixel(screenHeight * elemHeight / 100);
};

/**
* Event listener function that detects orientation change (every time it occurs) and triggers
* screen rerendering. It does that, by changing the state of the screen where the function is
* called. State changing occurs for a new state variable with the name 'orientation' that will
* always hold the current value of the orientation after the 1st orientation change.
* Invoke it inside the screen's constructor or in componentDidMount lifecycle method.
* @param {object} that Screen's class component this variable. The function needs it to
* invoke setState method and trigger screen rerender (this.setState()).
*/
const listenOrientationChange = that => {
Dimensions.addEventListener('change', newDimensions => {
// Retrieve and save new dimensions
screenWidth = newDimensions.window.width;
screenHeight = newDimensions.window.height;

// Trigger screen's rerender with a state update of the orientation variable
that.setState({
orientation: screenWidth < screenHeight ? 'portrait' : 'landscape'
});
});
};

/**
* Wrapper function that removes orientation change listener and should be invoked in
* componentWillUnmount lifecycle method of every class component (UI screen) that
* listenOrientationChange function has been invoked. This should be done in order to
* avoid adding new listeners every time the same component is re-mounted.
*/
const removeOrientationListener = () => {
Dimensions.removeEventListener('change', () => {});
};

export {
widthPercentageToDP,
heightPercentageToDP
heightPercentageToDP,
listenOrientationChange,
removeOrientationListener
};

0 comments on commit 9a8cd6b

Please sign in to comment.