flex、flexGrow、レスポンシブなサイズ設定
flexプロパティを使って、兄弟View間で利用可能な空間を比例配分し、画面幅に合わせて調整されるレイアウトを構築します
「flex、flexGrow、レスポンシブなサイズ設定」はCoddyKit上の無料React Native Academyレッスンです。 これはレッスン3/4です。 下記で完全なレッスンを無料で読むことができます。その後、ブラウザ内の組み込みコードエディタと24時間対応のAIチューターでハンズオン演習できます。 これはReact Native Academy学習パスの一部であり、ウェブとCoddyKitアプリ全体で進捗が同期されます。 React Native Academyコースには全4レッスンが含まれています。
このレッスンの一部はまだ翻訳されておらず、英語で表示されています。
The flex Property Explained
The flex property is a shorthand that sets how a View grows and shrinks to fill available space within its parent. In React Native, flex is similar to CSS's flex-grow — it represents the proportion of available space the component takes. Setting flex: 1 on a single child makes it fill all remaining space. When multiple siblings have flex values, the space is divided proportionally: a child with flex: 2 gets twice as much space as a sibling with flex: 1.
import { View } from 'react-native';
export default function FlexDemo() {
return (
<View style={{ flex: 1, flexDirection: 'column' }}>
{/* Takes 1/3 of height */}
<View style={{ flex: 1, backgroundColor: '#ff6b6b' }} />
{/* Takes 2/3 of height */}
<View style={{ flex: 2, backgroundColor: '#4f86f7' }} />
</View>
);
}flex: 1 on the Root Container
If your root App component or the outermost screen View doesn't have flex: 1, the component collapses to the size of its content — it does not fill the screen. This is one of the most common React Native bugs for beginners: the app appears to have no layout because the root View has zero height. Always set flex: 1 on the root-level View and any intermediate containers that should fill available space. Child Views without a fixed size or flex property will shrink to wrap their content.
import { View, Text, StyleSheet } from 'react-native';
// WRONG: root View has no flex, collapses to text height
function WrongLayout() {
return (
<View style={{ backgroundColor: '#f5f5f5' }}>
<Text>This View only wraps its content.</Text>
</View>
);
}
// CORRECT: flex: 1 fills the screen
function CorrectLayout() {
return (
<View style={{ flex: 1, backgroundColor: '#f5f5f5' }}>
<Text>This View fills the entire screen.</Text>
</View>
);
}flexGrow, flexShrink, and flexBasis
React Native's flex shorthand sets flexGrow, flexShrink, and flexBasis together. flexGrow controls how much a child grows into extra space. flexShrink controls how much it shrinks when space is tight. flexBasis sets the initial size before growing or shrinking (like CSS flex-basis). In practice, flex: 1 covers most use cases. Use flexShrink: 1 on a Text inside a row when you want it to shrink and show ellipsis instead of overflowing the row.
import { View, Text, StyleSheet } from 'react-native';
export default function FlexShrinkExample() {
return (
<View style={styles.row}>
<View style={styles.icon} />
{/* flexShrink: 1 allows text to shrink if the row is too small */}
<Text style={styles.label} numberOfLines={1}>
A very long label that could overflow without flexShrink
</Text>
<Text style={styles.badge}>NEW</Text>
</View>
);
}
const styles = StyleSheet.create({
row: { flexDirection: 'row', alignItems: 'center', padding: 12, gap: 8 },
icon: { width: 40, height: 40, borderRadius: 8, backgroundColor: '#4f86f7', flexShrink: 0 },
label: { flex: 1, flexShrink: 1, fontSize: 16, color: '#333' },
badge: { paddingHorizontal: 8, paddingVertical: 2, backgroundColor: '#ff6b6b', color: '#fff', borderRadius: 10, fontSize: 11, fontWeight: 'bold' },
});Dimensions API for Screen Size
To get the current screen width and height in JavaScript, use the Dimensions API from react-native. Dimensions.get('window') returns the visible app area (excluding system bars), while Dimensions.get('screen') returns the full physical screen. However, Dimensions is a static snapshot — it won't update if the user rotates the device. For responsive layouts that react to orientation changes, use the useWindowDimensions hook, which returns updated values on every resize.
import { View, Text, Dimensions, useWindowDimensions } from 'react-native';
// Static (doesn't update on rotation)
const { width, height } = Dimensions.get('window');
// Reactive (updates on rotation — preferred)
export default function ResponsiveScreen() {
const { width, height } = useWindowDimensions();
const isLandscape = width > height;
return (
<View style={{ flex: 1, padding: 16 }}>
<Text>Width: {Math.round(width)}</Text>
<Text>Height: {Math.round(height)}</Text>
<Text>Mode: {isLandscape ? 'Landscape' : 'Portrait'}</Text>
</View>
);
}Percentage Widths for Responsive Columns
Use percentage strings for width to create layouts that adapt to different screen sizes without hardcoding pixel values. A two-column grid uses width: '48%' on each card with a small gap. A three-column layout uses width: '32%'. The percentage is relative to the parent container's width. To ensure the math works, set the parent's width explicitly or make it flex: 1, and use flexWrap: 'wrap' on the row container so columns flow to the next line correctly.
import { View, StyleSheet } from 'react-native';
export default function TwoColumnGrid() {
return (
<View style={styles.grid}>
{[1, 2, 3, 4, 5, 6].map(n => (
<View key={n} style={styles.card} />
))}
</View>
);
}
const styles = StyleSheet.create({
grid: {
flexDirection: 'row',
flexWrap: 'wrap',
gap: 12,
padding: 16,
},
card: {
width: '47%', // ~2 per row with gap
height: 120,
backgroundColor: '#4f86f7',
borderRadius: 12,
},
});Combining flex with Fixed Dimensions
You can mix flex-based sizing with fixed width and height values in the same layout. A common pattern is a sidebar layout: a fixed-width side panel (e.g., width: 280) next to a content area with flex: 1 that fills the rest of the screen. The fixed-size panel takes exactly 280 points regardless of screen size, while the content panel grows or shrinks to use all remaining space. This also works for headers and footers: fixed height containers at top/bottom with a flex: 1 content area in between.
import { View, Text, StyleSheet } from 'react-native';
export default function MasterDetail() {
return (
<View style={styles.container}>
{/* Fixed-width sidebar */}
<View style={styles.sidebar}>
<Text style={{ color: '#fff' }}>Sidebar</Text>
</View>
{/* flex: 1 content fills remaining space */}
<View style={styles.content}>
<Text>Main content area</Text>
</View>
</View>
);
}
const styles = StyleSheet.create({
container: { flex: 1, flexDirection: 'row' },
sidebar: { width: 200, backgroundColor: '#333', padding: 16 },
content: { flex: 1, backgroundColor: '#f5f5f5', padding: 16 },
});useWindowDimensions for Adaptive Layouts
The useWindowDimensions hook re-renders your component whenever the device orientation changes or a multi-window layout resizes. Use it to dynamically switch between single-column (portrait) and two-column (landscape) layouts. Calculate the number of columns based on the window width: if width is above a threshold (e.g., 600), switch to two or three columns. This approach makes your app look good on phones, large phones, tablets, and even desktops with Expo Web — without writing separate layout components.
import { View, StyleSheet, useWindowDimensions } from 'react-native';
export default function AdaptiveGrid({ items }) {
const { width } = useWindowDimensions();
const numColumns = width >= 768 ? 3 : width >= 480 ? 2 : 1;
const cardWidth = (width - 32 - (numColumns - 1) * 12) / numColumns;
return (
<View style={styles.grid}>
{items.map(item => (
<View key={item.id} style={[styles.card, { width: cardWidth }]} />
))}
</View>
);
}
const styles = StyleSheet.create({
grid: { flexDirection: 'row', flexWrap: 'wrap', gap: 12, padding: 16 },
card: { height: 120, backgroundColor: '#4f86f7', borderRadius: 10 },
});minWidth, maxWidth, minHeight, maxHeight
Use minWidth, maxWidth, minHeight, and maxHeight to constrain how much a View can grow or shrink. These are useful for creating components that look good across a range of content sizes without breaking at extremes. For example, a button might have a minWidth: 120 so it is always touchable even for a single-character label, but a maxWidth: 320 so it never stretches across a full tablet screen. Combining these with flex: 1 and width: '100%' is the typical pattern for centered, bounded content on larger screens.
import { View, Text, StyleSheet } from 'react-native';
export default function BoundedContent() {
return (
<View style={styles.screen}>
{/* Content is at most 480px wide, centered */}
<View style={styles.content}>
<Text style={styles.text}>This content is bounded to look good on all screen sizes.</Text>
</View>
</View>
);
}
const styles = StyleSheet.create({
screen: { flex: 1, alignItems: 'center', backgroundColor: '#f5f5f5', padding: 16 },
content: {
width: '100%',
maxWidth: 480, // doesn't stretch on tablets/web
backgroundColor: '#fff',
borderRadius: 12,
padding: 20,
},
text: { fontSize: 16, lineHeight: 24, color: '#333' },
});Aspect Ratio for Consistent Proportions
The aspectRatio style property sets the width-to-height ratio of a component. When the width is set (or determined by flex), aspectRatio automatically computes the height to maintain the proportion. aspectRatio: 16/9 creates a widescreen video thumbnail. aspectRatio: 1 creates a perfect square. This is especially powerful for media content that must adapt to different screen widths — the height automatically scales proportionally without any calculations or JavaScript.
import { View, Image, StyleSheet } from 'react-native';
export default function VideoThumbnail() {
return (
<View style={styles.thumbnailContainer}>
<Image
source={{ uri: 'https://picsum.photos/640/360' }}
style={styles.thumbnail}
/>
</View>
);
}
const styles = StyleSheet.create({
thumbnailContainer: {
width: '100%',
},
thumbnail: {
width: '100%',
aspectRatio: 16 / 9, // height auto-computed = width * 9/16
borderRadius: 10,
},
});Three-Panel Responsive Layout
Bring together all the sizing concepts: flex, maxWidth, and useWindowDimensions to build a classic three-panel layout for a note-taking or email app. On small phones, only one panel shows at a time. On tablets in landscape, all three panels appear side by side using flex ratios. This adaptive pattern is achievable with React Native's Flexbox and dimension hooks — no complex CSS media queries or separate layouts needed.
import { View, useWindowDimensions, StyleSheet } from 'react-native';
export default function ThreePanel() {
const { width } = useWindowDimensions();
const isTablet = width >= 768;
if (!isTablet) {
// Phone: single panel
return <View style={{ flex: 1, backgroundColor: '#f5f5f5' }} />;
}
// Tablet: three panels
return (
<View style={styles.row}>
<View style={[styles.panel, { flex: 1 }]} />
<View style={[styles.panel, { flex: 2, backgroundColor: '#e8f0fe' }]} />
<View style={[styles.panel, { flex: 2 }]} />
</View>
);
}
const styles = StyleSheet.create({
row: { flex: 1, flexDirection: 'row' },
panel: { backgroundColor: '#f5f5f5', borderRightWidth: 1, borderRightColor: '#ddd' },
});Avoiding Layout Pitfalls
Common React Native layout pitfalls to watch for: missing flex: 1 on a container makes it collapse to zero height; percentage widths without a sized parent resolve to zero; fixed heights in deeply nested views cause clipping on small screens; minHeight instead of flex on scroll containers prevents proper sizing. Debug by temporarily adding backgroundColor tints to each View — you'll immediately see which boxes are sized correctly and which are collapsing. When a component is invisible, suspect a zero-height parent before looking at the component's own styles.
// Debugging checklist when a component is invisible:
// 1. Does its parent have flex: 1 or an explicit height?
// 2. Does the component itself have flex or height/width?
// 3. Are percentage dimensions resolving against a zero-width parent?
// 4. Is backgroundColor set (to verify the View is rendered but transparent)?
// Quick visibility check:
<View style={{ flex: 1, backgroundColor: 'rgba(255,0,0,0.1)' }}>
{/* If this shows red tint, the container is sized correctly */}
<YourComponent />
</View>Quick Check
Test your understanding of React Native Mobile Development concepts from this lesson.
Lesson Recap
In this lesson you learned: flex: 1 fills remaining available space proportionally, useWindowDimensions provides reactive screen dimensions for orientation-aware layouts, and aspectRatio automatically computes height from width to maintain consistent proportions. Next up we explore building a responsive card grid with Flexbox wrapping.
よくある質問
「flex、flexGrow、レスポンシブなサイズ設定」レッスンは無料ですか?
はい。「flex、flexGrow、レスポンシブなサイズ設定」の完全なテキストはこのウェブで無料で読めます。インタラクティブに演習し(組み込みコードエディタと24時間対応のAIチューター)、React Native Academyコースの残りをアンロックするには、CoddyKit PROにアップグレードしてください。 React Native Academyコースには全4レッスンが含まれています。
「flex、flexGrow、レスポンシブなサイズ設定」で何を学びますか?
flexプロパティを使って、兄弟View間で利用可能な空間を比例配分し、画面幅に合わせて調整されるレイアウトを構築します ブラウザで直接実行するハンズオンコードでReact Native Academyを演習し、24時間対応のAIチューターがレッスンを進める中での質問に答えます。
React Native Academyを始めるのに経験は必要ですか?
事前経験は必要ありません。CoddyKitのReact Native Academyは初級者から上級者向けに構成されているため、ここから始めるか最初から始めて、自分のペースで進むことができます。 これはレッスン3/4です。
「flex、flexGrow、レスポンシブなサイズ設定」レッスンにはどのくらい時間がかかりますか?
ほとんどのCoddyKitレッスンは約5~10分かかります。各レッスンはコンパクトでインタラクティブなので、着実に進歩し、ウェブとアプリ全体で正確に前回の場所から再開できます。
このReact Native Academyレッスンでコードを書いて実行できますか?
はい。すべてのReact Native Academyレッスンに組み込みコードエディタが含まれているため、ブラウザでリアルコードを書いて実行し、即座のAIフィードバックを取得できます。ローカル設定は不要です。
このコースのすべてのレッスン
- StyleSheet.createとインラインスタイル
- Flexboxの方向、justifyContent、alignItems
- flex、flexGrow、レスポンシブなサイズ設定
- レスポンシブなカードグリッドの構築