July 04, 2024
Media Query in React Native with Dimension API and useWindowDimensions Hook
In this post, we will explore how to implement media queries in React Native using the Dimension API. We will continue from my last blog post, and you can get the source code here. Let's break down the API and its usage.
Breaking Down the API
The Dimension API provides a method called get
, which takes a window
or screen
argument. On iOS, there is no difference between the two. On Android, screen
represents the entire available width and height including the status bar, whereas window
excludes the status bar.
The object returned from the get
method gives us access to properties such as width
, height
, scale
, and fontScale
.
const deviceWidth = Dimensions.get("window").width;
const deviceHeight = Dimensions.get("window").height;
const deviceScale = Dimensions.get("window").scale;
const deviceFontScale = Dimensions.get("window").fontScale;
Implementing in the NumberContainer Component
In the /components/Game/NumberContainer.tsx
file, we dynamically set the padding and margin of the container style based on a screen width of 380. We also adjust the font size of the number text similarly.
const deviceWidth = Dimensions.get("window").width;
const styles = StyleSheet.create({
container: {
padding: deviceWidth < 380 ? 12 : 24,
margin: deviceWidth < 380 ? 12 : 24,
borderWidth: 4,
borderRadius: 8,
borderColor: Colors.accent500,
alignItems: "center",
justifyContent: "center",
},
numberText: {
color: Colors.accent500,
fontSize: deviceWidth < 380 ? 28 : 36,
fontFamily: "open-sans-bold",
},
});
Implementing in the Card Component
In the /components/Ui/Card.tsx
file, we adjust the marginTop
property based on the device width, providing a responsive design for different screen sizes.
const deviceWidth = Dimensions.get("window").width;
const styles = StyleSheet.create({
card: {
padding: 16,
marginTop: deviceWidth < 380 ? 18 : 36,
marginHorizontal: 24,
borderRadius: 8,
backgroundColor: Colors.primary800,
justifyContent: "center", // align vertically
alignItems: "center", // Align horizontally
elevation: 4,
shadowColor: "black",
shadowOffset: { width: 0, height: 2 },
shadowRadius: 6,
shadowOpacity: 0.25,
},
});
Implementing in the GameOverScreen Component
In the GameOverScreen.tsx
file, we adjust the styles dynamically based on the device width, ensuring the layout adapts to different screen sizes.
const deviceWidth = Dimensions.get("window").width;
const styles = StyleSheet.create({
screenContainer: {
flex: 1,
padding: 24,
justifyContent: "center",
alignItems: "center",
},
imageContainer: {
width: deviceWidth < 380 ? 150 : 300,
height: deviceWidth < 380 ? 150 : 300,
borderRadius: deviceWidth < 380 ? 75 : 150,
borderWidth: 3,
color: Colors.primary800,
overflow: "hidden",
margin: 36,
},
image: {
width: "100%",
height: "100%",
},
summaryText: {
fontFamily: "open-sans",
fontSize: 24,
textAlign: "center",
marginBottom: 24,
},
highlight: {
fontFamily: "open-sans-bold",
color: Colors.primary500,
},
});
Handling Change of Orientation
The styles can break when you change orientation to landscape. To address this, we can use the height from the Dimension API to target it. However, the Dimension API is not reactive, meaning the styles will not react to orientation changes because it only runs once when the file is parsed. To solve this, React Native provides a hook useWindowDimensions
which we can call within the component itself. With this hook, we can get the device's width and height dynamically.
Implementing with useWindowDimensions Hook
In the StartGameScreen.tsx
file, we use the useWindowDimensions
hook to dynamically adjust the margin based on the device height.
const { width, height } = useWindowDimensions();
const marginTop = height < 380 ? 30 : 100;
// other code
<View style={[styles.screenContainer, { marginTop }]}>
// other code
Platform API
React Native also provides a Platform API to handle platform-specific code. We can use Platform.OS
in ternary statements or Platform.select
for conditional styles.
// Using Platform.OS
borderWidth: Platform.OS === "android" ? 2 : 0,
// Using Platform.select
borderWidth: Platform.select({ ios: 0, android: 2 }),
Platform-Specific Files
We can create platform-specific files by updating the compiler options in tsconfig.json
.
{
"extends": "expo/tsconfig.base",
"compilerOptions": {
"strict": true,
"moduleSuffixes": [".ios", ".android", ".native", ""]
}
}
Then, make a copy of the Title
file and name it Title.android.tsx
, and rename the other to Title.ios.tsx
. You can then make platform-specific styles respectively.
This concludes our exploration of media queries in React Native using the Dimension API and the useWindowDimensions
hook as well as platform specific styling with Platform API. This approach ensures that your application can adapt to different screen sizes and orientations seamlessly. Stay tuned for more updates and improvements in future posts!
Source Code: https://github.com/Intuneteq/guessing-game/tree/media-query
232 views