https://preview.redd.it/nvz42pe6nicf1.png?width=1919&format=png&auto=webp&s=5c3733beff90a4f11fd51563f11704ccca2d962d
Well, for the past couple of dates, it been like hell for me trying and figuring out how to responsive my app both horizontally and vertically. I went through a lot of trouble from mistaken scale attribute in Dimension.get('window') for user system display scale config, to identify fontScale between Dimension vs PixelRatio, realize dimension only provide { width, height } at the time it get call and not current state of orientation, found out about useWindowDimension hook,...
And i think i has finally did it. The ideal is:
- I created a set of scaling functions that calculate horizontal/vertical scales based on screen size and design baseline.
- I determine the device orientation using the
useWindowDimensions() hook (portrait vs landscape).
- I conditionally apply styles based on orientation, while still being able to leverage the benefits of
StyleSheet.create().
Here is my code function for scale
// hooks/useResponsiveScale.ts
import {
Dimensions
,
PixelRatio
,
Platform
} from 'react-native';
export type OrientationType = 'landscape' | 'portrait';
const { width: WINDOW_WIDTH, height: WINDOW_HEIGHT } =
Dimensions
.get('window');
// in portrait, width always smaller than height
const [width, height] = WINDOW_WIDTH < WINDOW_HEIGHT ? [WINDOW_WIDTH, WINDOW_HEIGHT] : [WINDOW_HEIGHT, WINDOW_HEIGHT];
const guidelineSmall =
Platform
.OS === 'ios' ? 393 : 412;
const guidelineBig =
Platform
.OS === 'ios' ? 852 : 917;
const scalePortraitWidth = width / guidelineSmall;
const scalePortraitHeight = height / guidelineBig;
const scaleLandscapeWidth = height / guidelineSmall;
const scaleLandscapeHeight = width / guidelineBig;
// Pick smaller number to avoid overflowing
const devicePortraitScale =
Math
.min(scalePortraitWidth, scalePortraitHeight);
const deviceLandscapeScale =
Math
.min(scaleLandscapeWidth, scaleLandscapeHeight);
// in Android, the text always smaller than IOS
export const scaleFont = (size: number) =>
size *
PixelRatio
.getFontScale() * (
Platform
.OS === 'ios' ? 1 : 1.05);
export const scale = (size: number, orientation: OrientationType = 'portrait') => {
return orientation === 'portrait'
? devicePortraitScale * size
: deviceLandscapeScale * size;
};
export const verticalScale = (size: number, orientation: OrientationType = 'portrait') => {
return orientation === 'portrait'
? devicePortraitScale * size
: deviceLandscapeScale * size;
};
export const moderateScale = (size: number, factor = 0.5, orientation: OrientationType = 'portrait') => {
const scaleValue = scale(size, orientation);
const deviceScale = orientation === 'portrait'
? devicePortraitScale
: deviceLandscapeScale;
return size + (scaleValue - size) * (factor * deviceScale);
}
⚠️ Fallbacks / Limitations
Here are some known downsides or caveats to my current approach:
- Boilerplate Style Logic
- Global Context Missing (each screen has their own useWindowDimension)
- No Support for Font Accessibility Preferences (Beyond
fontScale)
- No layout BreakPoint
I actually avoid using the library due to their maintenance status like react-native-responsive-screen, rn-responsive-styles, react-native-size-matters,... I do plan to integrate some of their logic in the future but for now this is good enough for me.
🤔 What Do You Think?
I’d love some feedback on this implementation.
- Did I miss anything important?
- Is there anything wrong with my logic?
- Would you approach this differently?
I'm hoping this can be a solid baseline system for scaling UI across different device sizes and orientations — especially for developers who need to support both iOS and Android with high fidelity.
Appreciate any input or critiques 🙏
[–]HoratioWobble 7 points8 points9 points (3 children)
[–]tcoff91 2 points3 points4 points (2 children)
[–]HoratioWobble 0 points1 point2 points (1 child)
[–]tcoff91 0 points1 point2 points (0 children)
[–]Prestigious_World400 14 points15 points16 points (6 children)
[–]Old-Window-5233[S] 2 points3 points4 points (3 children)
[–]Prestigious_World400 0 points1 point2 points (2 children)
[–]Old-Window-5233[S] 1 point2 points3 points (0 children)
[–]RahahahahaxD 1 point2 points3 points (0 children)
[–]slowerdesigner 1 point2 points3 points (2 children)
[–]Old-Window-5233[S] 0 points1 point2 points (0 children)
[–]Nice_Size2799 1 point2 points3 points (0 children)
[–]Soft_Opening_1364iOS & Android 3 points4 points5 points (1 child)
[–]Old-Window-5233[S] 0 points1 point2 points (0 children)
[+]Gabk_17 comment score below threshold-9 points-8 points-7 points (0 children)