From 6cc603a2d6b3678ad7b65e897de43f81dfe78fae Mon Sep 17 00:00:00 2001 From: marudy Date: Tue, 24 Apr 2018 12:03:24 +0300 Subject: [PATCH 1/6] Add listenOrientationChange method that listens orientation change and triggers a screen rerender. --- src/index.js | 32 ++++++++++++++++++++++++++++---- 1 file changed, 28 insertions(+), 4 deletions(-) diff --git a/src/index.js b/src/index.js index 6160d0a..851347d 100644 --- a/src/index.js +++ b/src/index.js @@ -1,14 +1,14 @@ // packages import { Dimensions, PixelRatio } from 'react-native'; -// Retrieve screen's width once +// Retrieve screen's width once const screenWidth = Dimensions.get('window').width; // Retrieve screen's height once 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. @@ -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); }; @@ -37,7 +37,31 @@ 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 and remove + * it in componentWillUnMount 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' + }); + }); +}; + export { widthPercentageToDP, - heightPercentageToDP + heightPercentageToDP, + listenOrientationChange }; From 69a436758ee11937a36d0457e06260b38e83122d Mon Sep 17 00:00:00 2001 From: marudy Date: Tue, 24 Apr 2018 12:04:28 +0300 Subject: [PATCH 2/6] Change comments for initial screen dimensions --- src/index.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/index.js b/src/index.js index 851347d..b7e5b35 100644 --- a/src/index.js +++ b/src/index.js @@ -1,10 +1,10 @@ // packages import { Dimensions, PixelRatio } from 'react-native'; -// Retrieve screen's width once -const screenWidth = Dimensions.get('window').width; +// Retrieve initial screen's width +const screenWidth = Dimensions.get('window').initial width; -// Retrieve screen's height once +// Retrieve initial screen's height const screenHeight = Dimensions.get('window').height; /** From 6fbf3c1d5498d963e417fa350366a4b1d2d2e073 Mon Sep 17 00:00:00 2001 From: marudy Date: Tue, 24 Apr 2018 12:31:10 +0300 Subject: [PATCH 3/6] Fix bug caused by previous comment change and also update comment --- src/index.js | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/src/index.js b/src/index.js index b7e5b35..d932135 100644 --- a/src/index.js +++ b/src/index.js @@ -2,7 +2,7 @@ import { Dimensions, PixelRatio } from 'react-native'; // Retrieve initial screen's width -const screenWidth = Dimensions.get('window').initial width; +const screenWidth = Dimensions.get('window').width; // Retrieve initial screen's height const screenHeight = Dimensions.get('window').height; @@ -42,8 +42,7 @@ const heightPercentageToDP = heightPercent => { * 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 and remove - * it in componentWillUnMount lifecycle method. + * 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()). */ @@ -63,5 +62,5 @@ const listenOrientationChange = (that) => { export { widthPercentageToDP, heightPercentageToDP, - listenOrientationChange + listenOrientationChange }; From a9a39cf23329589df07aa9370479c081f5582ce2 Mon Sep 17 00:00:00 2001 From: marudy Date: Tue, 24 Apr 2018 12:31:45 +0300 Subject: [PATCH 4/6] Add removeOrientationListener wrapper function --- src/index.js | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/src/index.js b/src/index.js index d932135..70d9b09 100644 --- a/src/index.js +++ b/src/index.js @@ -59,8 +59,19 @@ const listenOrientationChange = (that) => { }); }; +/** + * 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, - listenOrientationChange + listenOrientationChange, + removeOrientationListener }; From 5b7310e131f479c6193923af7e49acc5aeb46d98 Mon Sep 17 00:00:00 2001 From: marudy Date: Tue, 24 Apr 2018 12:32:11 +0300 Subject: [PATCH 5/6] Remove single argument parenthesis --- src/index.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/index.js b/src/index.js index 70d9b09..0f5bb5a 100644 --- a/src/index.js +++ b/src/index.js @@ -46,7 +46,7 @@ const heightPercentageToDP = heightPercent => { * @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) => { +const listenOrientationChange = that => { Dimensions.addEventListener('change', newDimensions => { // Retrieve and save new dimensions screenWidth = newDimensions.window.width; From 98a0ffd881d034e389543a21b288274b900a7e3c Mon Sep 17 00:00:00 2001 From: Tasos Maroudas Date: Tue, 24 Apr 2018 12:49:59 +0300 Subject: [PATCH 6/6] Add more examples on how to use the package and syntax highlighting --- README.md | 121 ++++++++++++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 113 insertions(+), 8 deletions(-) diff --git a/README.md b/README.md index b2ee775..2aa4ee0 100644 --- a/README.md +++ b/README.md @@ -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. +UPDATE: From version 1.1 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! @@ -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 ( @@ -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 ( + + + Login + + + ); + } +} + +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 ( + + + Login + + + ); + } +} + +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: