Updated March 28, 2023
Introduction to React Native Dimensions
The following article provides an outline for React Native Dimensions. Setting the dimensions of the window of the application is one of the most important aspects of creating an application. It makes the App more easier to use for the user. Dots per inch is used in React Native to measure the size of the UI and the things displayed. This measurement helps the app to look good on different screen sizes and varied density of the pixels across screens. An API known as Dimensions can be used to get the height and width of the user’s screen.
Syntax of Importing Dimensions:
import { Dimensions } from 'react-native';
Working on React Native Dimensions
For getting the dimensions of the user’s screen, Dimensions API can be used.
For fetching the screen height and width of the user’s screen:
Dimensions.get('screen').height;
Dimensions.get('screen').width;
Examples
Different examples are mentioned below:
Example #1
Piano using React Native Dimensions.
In the example below, we have successfully created a piano.
The files used to implement the code below are:
a. DimensionsProvider.js
import React from 'react';
import Dimensions from 'react-dimensions';
class DimensionsProvider extends React.Component {
render() {
return (
<div>
{this.props.children({
containerWidth: this.props.containerWidth,
containerHeight: this.props.containerHeight,
})}
</div>
);
}
}
export default Dimensions()(DimensionsProvider);
b. SoundfontProvider.js
import React from 'react';
import PropTypes from 'prop-types';
import Soundfont from 'soundfont-player';
class SoundfontProvider extends React.Component {
static propTypes = {
instrumentName: PropTypes.string.isRequired,
hostname: PropTypes.string.isRequired,
format: PropTypes.oneOf(['mp3', 'ogg']),
soundfont: PropTypes.oneOf(['MusyngKite', 'FluidR3_GM']),
audioContext: PropTypes.instanceOf(window.AudioContext),
render: PropTypes.func,
};
static defaultProps = {
format: 'mp3',
soundfont: 'MusyngKite',
instrumentName: 'acoustic_grand_piano',
};
constructor(props) {
super(props);
this.state = {
activeAudioNodes: {},
instrument: null,
};
}
componentDidMount() {
this.loadInstrument(this.props.instrumentName);
}
componentDidUpdate(prevProps, prevState) {
if (prevProps.instrumentName !== this.props.instrumentName) {
this.loadInstrument(this.props.instrumentName);
}
}
loadInstrument = instrumentName => {
this.setState({
instrument: null,
});
Soundfont.instrument(this.props.audioContext, instrumentName, {
format: this.props.format,
soundfont: this.props.soundfont,
nameToUrl: (name, soundfont, format) => {
return `${this.props.hostname}/${soundfont}/${name}-${format}.js`;
},
}).then(instrument => {
this.setState({
instrument,
});
});
};
playNote = midiNumber => {
this.props.audioContext.resume().then(() => {
const audioNode = this.state.instrument.play(midiNumber);
this.setState({
activeAudioNodes: Object.assign({}, this.state.activeAudioNodes, {
[midiNumber]: audioNode,
}),
});
});
};
stopNote = midiNumber => {
this.props.audioContext.resume().then(() => {
if (!this.state.activeAudioNodes[midiNumber]) {
return;
}
const audioNode = this.state.activeAudioNodes[midiNumber];
audioNode.stop();
this.setState({
activeAudioNodes: Object.assign({}, this.state.activeAudioNodes, {
[midiNumber]: null,
}),
});
});
};
stopAllNotes = () => {
this.props.audioContext.resume().then(() => {
const activeAudioNodes = Object.values(this.state.activeAudioNodes);
activeAudioNodes.forEach(node => {
if (node) {
node.stop();
}
});
this.setState({
activeAudioNodes: {},
});
});
};
render() {
return this.props.render({
isLoading: !this.state.instrument,
playNote: this.playNote,
stopNote: this.stopNote,
stopAllNotes: this.stopAllNotes,
});
}
}
export default SoundfontProvider;
c. index.js
import React from 'react';
import ReactDOM from 'react-dom';
import { Piano
, KeyboardShortcuts
, MidiNumbers } from 'react-piano';
import 'react-piano/dist/styles.css';
import DimensionsProvider from './DimensionsProvider';
import SoundfontProvider from './SoundfontProvider';
import './styles.css';
const audioContext = new (window.AudioContext || window.webkitAudioContext)();
const soundfontHostname = 'https://d1pzp51pvbm36p.cloudfront.net';
const noteRange = {
first: MidiNumbers.fromNote('c3'),
last: MidiNumbers.fromNote('f4'),
};
const keyboardShortcuts = KeyboardShortcuts.create({
firstNote: noteRange.first,
lastNote: noteRange.last,
keyboardConfig: KeyboardShortcuts.HOME_ROW,
});
function App() {
return (
<div>
<h1>Piano using React Native Dimesions</h1>
<div className="mt-5">
<p>
Responsive Basic Piano
</p>
<ResponsivePiano />
</div>
<div className="mt-5">
<p>Responsive Piano with Color Styling</p>
<ResponsivePiano className="PianoDarkTheme" />
</div>
</div>
);
}
function BasicPiano() {
return (
<SoundfontProvider
instrumentName="acoustic_grand_piano"
audioContext={audioContext}
hostname={soundfontHostname}
render={({ isLoading, playNote, stopNote }) => (
<Piano
noteRange={noteRange}
width={300}
playNote={playNote}
stopNote={stopNote}
disabled={isLoading}
keyboardShortcuts={keyboardShortcuts}
/>
)}
/>
);
}
function ResponsivePiano(props) {
return (
<DimensionsProvider>
{({ containerWidth, containerHeight }) => (
<SoundfontProvider
instrumentName="acoustic_grand_piano"
audioContext={audioContext}
hostname={soundfontHostname}
render={({ isLoading, playNote, stopNote }) => (
<Piano
noteRange={noteRange}
width={containerWidth}
playNote={playNote}
stopNote={stopNote}
disabled={isLoading}
{...props}
/>
)}
/>
)}
</DimensionsProvider>
);
}
const rootElement = document.getElementById('root');
ReactDOM.render(<App />, rootElement);
d. styles.css
.PianoDarkTheme .ReactPiano__Key--accidental {
background: #83de33;
border: 2px solid #1f1719;
}
.PianoDarkTheme .ReactPiano__Key--natural {
background: #c43df5;
border: 2px solid #0d0b0b;
margin-right: 0;
}
.PianoDarkTheme .ReactPiano__Key--active.ReactPiano__Key--accidental {
background: #a11d75;
}
.PianoDarkTheme .ReactPiano__Key--active.ReactPiano__Key--natural {
background: #c91c3f;
}
Output:
Example #2
Responsive Dimensions.
In the example below, we have successfully created responsive dimensions.
The files used to implement the code below are:
a. Context.js
import React
{ createContext
, useReducer } from "react";
export const Context = createContext(null);
export const ContextProvider = ({ children }) => {
const ADD_ITEM = "ADD_ITEM";
const SET_ACTIVE_ITEM = "SET_ACTIVE_ITEM";
const initialState = {
items: [],
activeItem: 0
};
function reducer(state, action) {
switch (action.type) {
case ADD_ITEM:
return {
...state,
items: [...state.items, action.item]
};
case SET_ACTIVE_ITEM:
return {
...state,
activeItem: action.activeItem
};
default:
return initialState;
}
}
const [state, dispatch] = useReducer(reducer, initialState);
return (
<Context.Provider value={{ state, dispatch }}>{children}</Context.Provider>
);
};
b. Item.js
import React
, { useContext
, useEffect } from "react";
import styled from "styled-components";
import useDimensios from "react-use-dimensions";
import { Context } from "./Context";
const ItemWrapper = styled.div`
flex: 0 0 auto;
&:not(:last-child) {
padding-right: ${props => props.gap}px;
}
`;
const Item = ({ children, gap, padding }) => {
const { dispatch } = useContext(Context);
const [itemRef, { x }] = useDimensios();
useEffect(() => {
x && dispatch({ type: "ADD_ITEM", item: x - padding });
}, [x]);
return (
<ItemWrapper ref={itemRef} gap={gap}>
{children}
</ItemWrapper>
);
};
export default Item;
c. Track.js
import React
, { useContext } from "react";
import styled from "styled-components";
import { motion
, useAnimation } from "framer-motion";
import useDimensions from "react-use-dimensions";
import useWindowSize from "@rehooks/window-size";
import { Context } from "./Context";
const Wrapper = styled.div`
width: 100%;
`;
const StyledTrack = styled(motion.div)`
display: flex;
flex-wrap: nowrap;
min-width: min-content;
padding: ${props => props.padding}px;
cursor: grab;
&:active {
cursor: grabbing;
}
`;
const Track = ({ children, padding, velocity, transition }) => {
const [trackRef, trackDimensions] = useDimensions();
const windowDimensions = useWindowSize();
const controls = useAnimation();
const { state
, dispatch
} = useContext(Context);
const negativeItems = state.items.map(
item => item * -1 + trackDimensions.x || 0
);
function onDragEnd(event, info) {
const offset = info.offset.x;
const correctedVelocity = info.velocity.x * velocity;
const direction = correctedVelocity < 0 || offset < 0 ? 1 : -1;
const startPosition = info.point.x - offset;
const endOffset =
direction === 1
? Math.min(correctedVelocity, offset)
: Math.max(correctedVelocity, offset);
const endPosition = startPosition + endOffset;
const closestPosition = negativeItems.reduce((prev, curr) =>
Math.abs(curr - endPosition) < Math.abs(prev - endPosition) ? curr : prev
);
const activeSlide = negativeItems.indexOf(closestPosition);
dispatch({ type: "SET_ACTIVE_ITEM", activeItem: activeSlide });
controls.start({
x: Math.max(
closestPosition,
windowDimensions.innerWidth -
trackDimensions.width -
trackDimensions.x || 0
),
transition
});
}
return (
<Wrapper>
<StyledTrack
ref={trackRef}
padding={padding}
animate={controls}
drag="x"
dragConstraints={{
left:
windowDimensions.innerWidth -
trackDimensions.width -
trackDimensions.x,
right: 0 + trackDimensions.x
}}
onDragEnd={onDragEnd}
>
{children}
</StyledTrack>
</Wrapper>
);
};
export default Track;
d. index.js (MotionSlider folder)
import React from "react";
import { ContextProvider } from "./Context";
import Track from "./Track";
import Item from "./Item";
const MotionSlider = ({ children, padding, gap, velocity, transition }) => {
return (
<ContextProvider>
<Track padding={padding} velocity={velocity} transition={transition}>
{children.map((child, i) => (
<Item key={i} gap={gap} padding={padding}>
{child}
</Item>
))}
</Track>
</ContextProvider>
);
};
MotionSlider.defaultProps = {
padding: 45,
gap: 40,
velocity: 0.6,
transition: { type: "spring", damping: 450 }
};
export default MotionSlider;
e. index.js
import React from "react";
import ReactDOM from "react-dom";
import styled
, { createGlobalStyle } from "styled-components";
import reset from "styled-reset-advanced";
import MotionSlider from "./MotionSlider";
function random(min, max) {
return Math.floor(
Math.random(
)
* (max - min
+ 1) + min
);
}
const GlobalStyle = createGlobalStyle`
${reset}
body { overflow-x: hidden; }
`;
const Wrapper = styled.div``;
const Element = styled.div`
width: 26px;
height: 380px;
background: black;
`;
function App() {
return (
<Wrapper>
<GlobalStyle />
<MotionSlider>
{[...Array(10)].map((item, i) => (
<Element
key={i}
style={{ opacity: Math.random() }}
/>
))}
</MotionSlider>
</Wrapper>
);
}
const rootElement = document.getElementById("root");
ReactDOM.render(<App />, rootElement);
Output:
Conclusion
On the basis of the above article, we saw how to fetch the dimensions of the user’s screen and to define our application according to it. This enhances the user experience of the application and makes it easy to use. The examples we saw above will help in the application.
Recommended Articles
This is a guide to React Native Dimensions. Here we discuss the introduction, working along with the examples respectively. You may also have a look at the following articles to learn more –