React Native布局与Flexbox #

概述 #

React Native 使用 Flexbox(弹性盒模型)作为主要的布局系统。Flexbox 提供了一种高效的方式来排列、对齐和分配容器中元素的空间。

Flexbox 基础 #

主轴与交叉轴 #

在 Flexbox 中,有两个重要的概念:

  • 主轴(Main Axis):元素排列的方向
  • 交叉轴(Cross Axis):与主轴垂直的方向
text
flexDirection: 'row'          flexDirection: 'column'
┌─────────────────────┐       ┌─────────────────────┐
│ ┌───┐ ┌───┐ ┌───┐   │       │ ┌─────────────────┐ │
│ │ 1 │ │ 2 │ │ 3 │   │       │ │       1         │ │
│ └───┘ └───┘ └───┘   │       │ └─────────────────┘ │
│   ←── 主轴 ──→      │       │ ┌─────────────────┐ │
│       ↓ 交叉轴      │       │ │       2         │ │
└─────────────────────┘       │ └─────────────────┘ │
                              │ ┌─────────────────┐ │
                              │ │       3         │ │
                              │ └─────────────────┘ │
                              │   ↑ 主轴            │
                              │   ← 交叉轴 →        │
                              └─────────────────────┘

flexDirection #

决定主轴方向,即子元素的排列方向。

column(默认) #

垂直方向,从上到下:

tsx
const ColumnExample = () => {
  return (
    <View style={styles.container}>
      <View style={styles.box1} />
      <View style={styles.box2} />
      <View style={styles.box3} />
    </View>
  );
};

const styles = StyleSheet.create({
  container: {
    flex: 1,
    flexDirection: 'column',
    backgroundColor: '#f5f5f5',
  },
  box1: {height: 100, backgroundColor: '#FF6B6B'},
  box2: {height: 100, backgroundColor: '#4ECDC4'},
  box3: {height: 100, backgroundColor: '#45B7D1'},
});

row #

水平方向,从左到右:

tsx
const RowExample = () => {
  return (
    <View style={styles.container}>
      <View style={styles.box1} />
      <View style={styles.box2} />
      <View style={styles.box3} />
    </View>
  );
};

const styles = StyleSheet.create({
  container: {
    flex: 1,
    flexDirection: 'row',
    backgroundColor: '#f5f5f5',
  },
  box1: {width: 100, backgroundColor: '#FF6B6B'},
  box2: {width: 100, backgroundColor: '#4ECDC4'},
  box3: {width: 100, backgroundColor: '#45B7D1'},
});

反向方向 #

  • column-reverse:从下到上
  • row-reverse:从右到左

justifyContent #

定义子元素在主轴上的对齐方式。

tsx
const JustifyContentExample = () => {
  return (
    <ScrollView>
      <Text>flex-start</Text>
      <View style={[styles.row, styles.flexStart]}>
        <View style={styles.box} />
        <View style={styles.box} />
        <View style={styles.box} />
      </View>

      <Text>center</Text>
      <View style={[styles.row, styles.center]}>
        <View style={styles.box} />
        <View style={styles.box} />
        <View style={styles.box} />
      </View>

      <Text>flex-end</Text>
      <View style={[styles.row, styles.flexEnd]}>
        <View style={styles.box} />
        <View style={styles.box} />
        <View style={styles.box} />
      </View>

      <Text>space-between</Text>
      <View style={[styles.row, styles.spaceBetween]}>
        <View style={styles.box} />
        <View style={styles.box} />
        <View style={styles.box} />
      </View>

      <Text>space-around</Text>
      <View style={[styles.row, styles.spaceAround]}>
        <View style={styles.box} />
        <View style={styles.box} />
        <View style={styles.box} />
      </View>

      <Text>space-evenly</Text>
      <View style={[styles.row, styles.spaceEvenly]}>
        <View style={styles.box} />
        <View style={styles.box} />
        <View style={styles.box} />
      </View>
    </ScrollView>
  );
};

const styles = StyleSheet.create({
  row: {
    flexDirection: 'row',
    height: 100,
    backgroundColor: '#f5f5f5',
    marginBottom: 20,
  },
  box: {
    width: 50,
    backgroundColor: '#007AFF',
  },
  flexStart: {justifyContent: 'flex-start'},
  center: {justifyContent: 'center'},
  flexEnd: {justifyContent: 'flex-end'},
  spaceBetween: {justifyContent: 'space-between'},
  spaceAround: {justifyContent: 'space-around'},
  spaceEvenly: {justifyContent: 'space-evenly'},
});

对齐方式对比 #

效果
flex-start 从起点开始排列
center 居中排列
flex-end 从终点开始排列
space-between 两端对齐,中间平分
space-around 每个元素两侧间隔相等
space-evenly 所有间隔完全相等

alignItems #

定义子元素在交叉轴上的对齐方式。

tsx
const AlignItemsExample = () => {
  return (
    <ScrollView>
      <Text>flex-start</Text>
      <View style={[styles.row, styles.alignStart]}>
        <View style={[styles.box, {height: 50}]} />
        <View style={[styles.box, {height: 80}]} />
        <View style={[styles.box, {height: 60}]} />
      </View>

      <Text>center</Text>
      <View style={[styles.row, styles.alignCenter]}>
        <View style={[styles.box, {height: 50}]} />
        <View style={[styles.box, {height: 80}]} />
        <View style={[styles.box, {height: 60}]} />
      </View>

      <Text>flex-end</Text>
      <View style={[styles.row, styles.alignEnd]}>
        <View style={[styles.box, {height: 50}]} />
        <View style={[styles.box, {height: 80}]} />
        <View style={[styles.box, {height: 60}]} />
      </View>

      <Text>stretch</Text>
      <View style={[styles.row, styles.alignStretch]}>
        <View style={styles.boxNoHeight} />
        <View style={styles.boxNoHeight} />
        <View style={styles.boxNoHeight} />
      </View>
    </ScrollView>
  );
};

const styles = StyleSheet.create({
  row: {
    flexDirection: 'row',
    height: 120,
    backgroundColor: '#f5f5f5',
    marginBottom: 20,
  },
  box: {
    width: 50,
    backgroundColor: '#007AFF',
  },
  boxNoHeight: {
    width: 50,
    backgroundColor: '#007AFF',
  },
  alignStart: {alignItems: 'flex-start'},
  alignCenter: {alignItems: 'center'},
  alignEnd: {alignItems: 'flex-end'},
  alignStretch: {alignItems: 'stretch'},
});

flex 属性 #

flex: 1 #

让元素填充剩余空间:

tsx
const FlexExample = () => {
  return (
    <View style={styles.container}>
      <View style={styles.header}>
        <Text>Header</Text>
      </View>
      <View style={styles.content}>
        <Text>Content - fills remaining space</Text>
      </View>
      <View style={styles.footer}>
        <Text>Footer</Text>
      </View>
    </View>
  );
};

const styles = StyleSheet.create({
  container: {
    flex: 1,
    backgroundColor: '#f5f5f5',
  },
  header: {
    height: 60,
    backgroundColor: '#007AFF',
    justifyContent: 'center',
    alignItems: 'center',
  },
  content: {
    flex: 1,
    backgroundColor: '#fff',
    justifyContent: 'center',
    alignItems: 'center',
  },
  footer: {
    height: 60,
    backgroundColor: '#333',
    justifyContent: 'center',
    alignItems: 'center',
  },
});

flex 比例 #

多个元素按比例分配空间:

tsx
const FlexRatioExample = () => {
  return (
    <View style={styles.container}>
      <View style={[styles.box, {flex: 1}]}>
        <Text>flex: 1</Text>
      </View>
      <View style={[styles.box, {flex: 2}]}>
        <Text>flex: 2</Text>
      </View>
      <View style={[styles.box, {flex: 1}]}>
        <Text>flex: 1</Text>
      </View>
    </View>
  );
};

const styles = StyleSheet.create({
  container: {
    flex: 1,
    flexDirection: 'row',
    backgroundColor: '#f5f5f5',
  },
  box: {
    backgroundColor: '#007AFF',
    justifyContent: 'center',
    alignItems: 'center',
    margin: 2,
  },
});

flexGrow, flexShrink, flexBasis #

tsx
const styles = StyleSheet.create({
  grow: {
    flexGrow: 1,
  },
  shrink: {
    flexShrink: 1,
  },
  basis: {
    flexBasis: 100,
  },
});

flexWrap #

控制元素是否换行。

nowrap(默认) #

不换行,元素可能溢出:

tsx
const NoWrapExample = () => {
  return (
    <View style={styles.container}>
      {[1, 2, 3, 4, 5, 6].map(i => (
        <View key={i} style={styles.box}>
          <Text>{i}</Text>
        </View>
      ))}
    </View>
  );
};

const styles = StyleSheet.create({
  container: {
    flexDirection: 'row',
    flexWrap: 'nowrap',
    backgroundColor: '#f5f5f5',
  },
  box: {
    width: 80,
    height: 80,
    backgroundColor: '#007AFF',
    margin: 4,
    justifyContent: 'center',
    alignItems: 'center',
  },
});

wrap #

换行显示:

tsx
const WrapExample = () => {
  return (
    <View style={[styles.container, {flexWrap: 'wrap'}]}>
      {/* 同上 */}
    </View>
  );
};

alignSelf #

允许单个元素覆盖父容器的 alignItems 设置:

tsx
const AlignSelfExample = () => {
  return (
    <View style={[styles.container, {alignItems: 'center'}]}>
      <View style={[styles.box, {alignSelf: 'flex-start'}]}>
        <Text>flex-start</Text>
      </View>
      <View style={styles.box}>
        <Text>center (inherited)</Text>
      </View>
      <View style={[styles.box, {alignSelf: 'flex-end'}]}>
        <Text>flex-end</Text>
      </View>
      <View style={[styles.box, {alignSelf: 'stretch'}]}>
        <Text>stretch</Text>
      </View>
    </View>
  );
};

实用布局模式 #

居中布局 #

tsx
const CenterLayout = () => {
  return (
    <View style={styles.container}>
      <View style={styles.centered}>
        <Text>Centered Content</Text>
      </View>
    </View>
  );
};

const styles = StyleSheet.create({
  container: {
    flex: 1,
    justifyContent: 'center',
    alignItems: 'center',
  },
  centered: {
    padding: 20,
    backgroundColor: '#007AFF',
  },
});

等分布局 #

tsx
const EqualDistribution = () => {
  return (
    <View style={styles.row}>
      {[1, 2, 3, 4].map(i => (
        <View key={i} style={styles.equalItem}>
          <Text>{i}</Text>
        </View>
      ))}
    </View>
  );
};

const styles = StyleSheet.create({
  row: {
    flexDirection: 'row',
  },
  equalItem: {
    flex: 1,
    height: 50,
    backgroundColor: '#007AFF',
    margin: 2,
    justifyContent: 'center',
    alignItems: 'center',
  },
});

固定侧边栏 #

tsx
const SidebarLayout = () => {
  return (
    <View style={styles.container}>
      <View style={styles.sidebar}>
        <Text>Sidebar</Text>
      </View>
      <View style={styles.content}>
        <Text>Main Content</Text>
      </View>
    </View>
  );
};

const styles = StyleSheet.create({
  container: {
    flex: 1,
    flexDirection: 'row',
  },
  sidebar: {
    width: 200,
    backgroundColor: '#333',
  },
  content: {
    flex: 1,
    backgroundColor: '#fff',
  },
});

底部固定 #

tsx
const BottomFixedLayout = () => {
  return (
    <View style={styles.container}>
      <ScrollView style={styles.content}>
        <Text>Scrollable content...</Text>
      </ScrollView>
      <View style={styles.footer}>
        <TouchableOpacity style={styles.button}>
          <Text style={styles.buttonText}>Submit</Text>
        </TouchableOpacity>
      </View>
    </View>
  );
};

const styles = StyleSheet.create({
  container: {
    flex: 1,
  },
  content: {
    flex: 1,
  },
  footer: {
    padding: 16,
    backgroundColor: '#fff',
    borderTopWidth: 1,
    borderTopColor: '#eee',
  },
  button: {
    backgroundColor: '#007AFF',
    padding: 16,
    borderRadius: 8,
    alignItems: 'center',
  },
  buttonText: {
    color: '#fff',
    fontSize: 16,
    fontWeight: '600',
  },
});

卡片网格 #

tsx
const CardGrid = () => {
  const data = Array.from({length: 6}, (_, i) => i + 1);

  return (
    <View style={styles.container}>
      {data.map(item => (
        <View key={item} style={styles.card}>
          <Text>Card {item}</Text>
        </View>
      ))}
    </View>
  );
};

const styles = StyleSheet.create({
  container: {
    flex: 1,
    flexDirection: 'row',
    flexWrap: 'wrap',
    padding: 8,
  },
  card: {
    width: '50%',
    padding: 8,
  },
  cardInner: {
    backgroundColor: '#fff',
    borderRadius: 8,
    padding: 16,
    height: 150,
    shadowColor: '#000',
    shadowOffset: {width: 0, height: 2},
    shadowOpacity: 0.1,
    shadowRadius: 4,
    elevation: 3,
  },
});

常见问题 #

为什么 flex: 1 不生效? #

确保父容器有确定的尺寸:

tsx
const WrongExample = () => {
  return (
    <View>
      <View style={{flex: 1}}> {/* 不会生效,父容器没有高度 */}
        <Text>Content</Text>
      </View>
    </View>
  );
};

const CorrectExample = () => {
  return (
    <View style={{flex: 1}}> {/* 父容器有确定高度 */}
      <View style={{flex: 1}}>
        <Text>Content</Text>
      </View>
    </View>
  );
};

如何实现固定宽高比? #

tsx
const AspectRatioBox = () => {
  const [width, setWidth] = useState(0);

  return (
    <View
      style={styles.container}
      onLayout={e => setWidth(e.nativeEvent.layout.width)}>
      <View style={[styles.box, {height: width * 0.75}]}>
        <Text>16:9 Aspect Ratio</Text>
      </View>
    </View>
  );
};

const styles = StyleSheet.create({
  container: {
    padding: 16,
  },
  box: {
    backgroundColor: '#007AFF',
    justifyContent: 'center',
    alignItems: 'center',
  },
});

总结 #

Flexbox 是 React Native 的核心布局系统:

  • flexDirection:决定主轴方向
  • justifyContent:主轴对齐
  • alignItems:交叉轴对齐
  • flex:弹性比例
  • flexWrap:换行控制
  • alignSelf:单独对齐

掌握 Flexbox 可以轻松实现各种复杂的布局需求。

继续学习 事件处理,了解触摸事件和手势处理。

最后更新:2026-03-28