React Native 样式与布局

样式

在 React Native 中,仍然是使用 JavaScript 来写样式,所有的核心组件都接受名为 style 的属性,这些样式名基本上都遵循 web 上的 CSS 属性名

RN 中的样式与 CSS 的不同
1、没有继承性
RN 中的继承只发生在 Text 组件上

2、样式名采用小驼峰命名
fontSize VS font-size

3、所有尺寸都没有单位
width: 100

4、有一些特殊的样式名
marginHorizontal(水平外边距), marginVertical (垂直外边距)

RN 样式的声明方式
1、通过 style 属性直接声明
属性值为对象:<组件 style={{样式}} />
属性值为数组:<组件 style={[{样式1}, ..., {样式N}]} />

2、在 style 属性中调用 StyleSheet 声明的样式
引入:import {StyleSheet, View} from 'react-native'
声明:const styles = StyleSheet.create({foo: {样式1}, bar: {样式2}})
使用:<View style={[styles.foo, styles.bar]}>内容</View>
import {StyleSheet, Text, View} from 'react-native';
import React, {Component} from 'react';

export default class index extends Component {
  render() {
    return (
      <View>
        <Text style={{fontSize: 60}}>index</Text>
        <Text style={[{color: 'red'}, {fontSize: 30}]}>React Native</Text>
        <Text style={[{color: 'red'}, {color: 'green'}]}>React Native</Text>
        <Text style={styles.mainTitle}>Flutter</Text>
        <Text style={[styles.subTitle]}>React</Text>
      </View>
    );
  }
}

const styles = StyleSheet.create({
  mainTitle: {
    fontSize: 40, // number 类型
    fontWeight: 'bold', // string 类型
    marginVertical: 30, // number 类型
  },
  subTitle: {
    fontSize: 20,
    fontWeight: '400', // string 类型
  },
});

 

使用 Flexbox 布局

在 RN 中使用 flexbox 规则来指定某个组件的子元素的布局,flexbox 可以在不同屏幕尺寸上提供一致的布局结构

flexbox 术语

容器(container)
采用 flex 布局的元素,称为 flex 容器,简称 容器

项目(item)
容器所有的子元素,称为 flex 项目,简称 项目

主轴(main axis)
交叉轴(cross axis)

flexbox 属性

flex
flex 属性决定元素在主轴上如何 填满 可用区域。整个区域会根据每个元素设置的 flex 属性值被分割成多个部分
在下面的例子中,在设置了宽高为100%的容器中,有红色、黄色和绿色三个子 View,红色设置了 flex:1,黄色设置了 flex:2,绿色设置了 flex:3,这意味着 红色 view 占据整个容器的 1/6,黄色 view 占据整个容器的 2/6,绿色 view 占据整个容器的 3/6
import React from 'react';
import {View, StyleSheet, Dimensions} from 'react-native';

const Flex = () => {
  return (
    <View style={[styles.container]}>
      <View style={{flex: 1, backgroundColor: 'red'}} />
      <View style={{flex: 2, backgroundColor: 'darkorange'}} />
      <View style={{flex: 3, backgroundColor: 'green'}} />
    </View>
  );
};

const styles = StyleSheet.create({
  container: {
    width: Dimensions.get('window').width,
    height: Dimensions.get('window').height,
    padding: 20,
    backgroundColor: '#f0f0f0',
  },
});

export default Flex;

 

flexDirection
声明主轴的方向,子元素是应该沿着 水平轴(row)方向排列,还是沿着 竖直轴(column)方向排列
在 Web 里默认是 水平轴(row),在 RN 里默认是 垂直轴(column)
import React from 'react';
import {View, Text, StyleSheet} from 'react-native';

const FlexDirection = () => {
  return (
    <View>
      <View style={styles.card}>
        <Text style={styles.title}>flexDirection: column(默认)</Text>
        <View style={[styles.container, {flexDirection: 'column'}]}>
          <View style={[styles.box, {backgroundColor: 'powderblue'}]} />
          <View style={[styles.box, {backgroundColor: 'skyblue'}]} />
          <View style={[styles.box, {backgroundColor: 'steelblue'}]} />
        </View>
      </View>
      <View style={styles.card}>
        <Text style={styles.title}>flexDirection: row</Text>
        <View style={[styles.container, {flexDirection: 'row'}]}>
          <View style={[styles.box, {backgroundColor: 'powderblue'}]} />
          <View style={[styles.box, {backgroundColor: 'skyblue'}]} />
          <View style={[styles.box, {backgroundColor: 'steelblue'}]} />
        </View>
      </View>
      <View style={styles.card}>
        <Text style={styles.title}>flexDirection: row-reverse</Text>
        <View style={[styles.container, {flexDirection: 'row-reverse'}]}>
          <View style={[styles.box, {backgroundColor: 'powderblue'}]} />
          <View style={[styles.box, {backgroundColor: 'skyblue'}]} />
          <View style={[styles.box, {backgroundColor: 'steelblue'}]} />
        </View>
      </View>
      <View style={styles.card}>
        <Text style={styles.title}>flexDirection: column-reverse</Text>
        <View style={[styles.container, {flexDirection: 'column-reverse'}]}>
          <View style={[styles.box, {backgroundColor: 'powderblue'}]} />
          <View style={[styles.box, {backgroundColor: 'skyblue'}]} />
          <View style={[styles.box, {backgroundColor: 'steelblue'}]} />
        </View>
      </View>
    </View>
  );
};

const styles = StyleSheet.create({
  title: {
    textAlign: 'center',
    fontSize: 24,
    fontWeight: '600',
  },
  card: {
    marginTop: 10,
    backgroundColor: 'oldlace',
  },
  container: {
    marginTop: 10,
  },
  box: {
    width: 50,
    height: 50,
  },
});

export default FlexDirection;

 

justifyContent
在组件的 style 中指定 justifyContent 可以决定其子元素沿着 主轴 的排列方式

取值:
flex-start: 默认值,左对齐
flex-end: 右对齐
center: 居中
space-between: 两端对齐,项目之间的间隔都相等
space-around: 每个项目两侧的间隔相等。所以,项目之间的间隔比项目与两端的间隔大一倍
space-evenly:每个项目之间的间隔相等,均匀排列每个项目
import React from 'react';
import {View, Text, StyleSheet} from 'react-native';

const JustifyContent = () => {
  return (
    <View>
      <View style={styles.card}>
        <Text style={styles.title}>justifyContent: flex-start</Text>
        <View style={[styles.container, {justifyContent: 'flex-start'}]}>
          <View style={[styles.box, {backgroundColor: 'powderblue'}]} />
          <View style={[styles.box, {backgroundColor: 'skyblue'}]} />
          <View style={[styles.box, {backgroundColor: 'steelblue'}]} />
        </View>
      </View>
      <View style={styles.card}>
        <Text style={styles.title}>justifyContent: flex-end</Text>
        <View style={[styles.container, {justifyContent: 'flex-end'}]}>
          <View style={[styles.box, {backgroundColor: 'powderblue'}]} />
          <View style={[styles.box, {backgroundColor: 'skyblue'}]} />
          <View style={[styles.box, {backgroundColor: 'steelblue'}]} />
        </View>
      </View>
      <View style={styles.card}>
        <Text style={styles.title}>justifyContent: center</Text>
        <View style={[styles.container, {justifyContent: 'center'}]}>
          <View style={[styles.box, {backgroundColor: 'powderblue'}]} />
          <View style={[styles.box, {backgroundColor: 'skyblue'}]} />
          <View style={[styles.box, {backgroundColor: 'steelblue'}]} />
        </View>
      </View>
      <View style={styles.card}>
        <Text style={styles.title}>justifyContent: space-between</Text>
        <View style={[styles.container, {justifyContent: 'space-between'}]}>
          <View style={[styles.box, {backgroundColor: 'powderblue'}]} />
          <View style={[styles.box, {backgroundColor: 'skyblue'}]} />
          <View style={[styles.box, {backgroundColor: 'steelblue'}]} />
        </View>
      </View>
      <View style={styles.card}>
        <Text style={styles.title}>justifyContent: space-around</Text>
        <View style={[styles.container, {justifyContent: 'space-around'}]}>
          <View style={[styles.box, {backgroundColor: 'powderblue'}]} />
          <View style={[styles.box, {backgroundColor: 'skyblue'}]} />
          <View style={[styles.box, {backgroundColor: 'steelblue'}]} />
        </View>
      </View>
      <View style={styles.card}>
        <Text style={styles.title}>justifyContent: space-evenly</Text>
        <View style={[styles.container, {justifyContent: 'space-evenly'}]}>
          <View style={[styles.box, {backgroundColor: 'powderblue'}]} />
          <View style={[styles.box, {backgroundColor: 'skyblue'}]} />
          <View style={[styles.box, {backgroundColor: 'steelblue'}]} />
        </View>
      </View>
    </View>
  );
};

const styles = StyleSheet.create({
  title: {
    textAlign: 'center',
    fontSize: 24,
    fontWeight: '600',
  },
  card: {
    marginTop: 10,
    backgroundColor: 'oldlace',
  },
  container: {
    marginTop: 10,
    flexDirection: 'row',
  },
  box: {
    width: 50,
    height: 50,
  },
});

export default JustifyContent;

 

alignItems
在组件的 style 中指定 alignItems 可以决定其子元素沿着 交叉轴 的排列方式

取值:
stretch: 默认值,根据容器交叉轴的高度撑满容器子元素
注意:要使 stretch 选项生效的话,子元素在 交叉轴 方向上不能有固定的尺寸
flex-end: 右对齐
center: 居中
space-between: 两端对齐,项目之间的间隔都相等
space-around: 每个项目两侧的间隔相等。所以,项目之间的间隔比项目与两端的间隔大一倍
space-evenly:每个项目之间的间隔相等,均匀排列每个项目

alignSelf
alignSelf 和 alignItems 具有相同的取值属性和作用,区别是:
alignItems 作用于容器下所有的子元素
alignSelf 作用于单个子元素,并且会覆盖 alignItems 指定的属性
import React from 'react';
import {View, Text, ScrollView, StyleSheet} from 'react-native';

const AlignItems = () => {
  return (
    <ScrollView>
      <View style={styles.card}>
        <Text style={styles.title}>alignItems: stretch(默认)</Text>
        <View style={[styles.container, {alignItems: 'stretch'}]}>
          <View style={[styles.box, {backgroundColor: 'powderblue'}]} />
          <View style={[styles.box, {backgroundColor: 'skyblue'}]} />
          <View style={[styles.box, {backgroundColor: 'steelblue'}]} />
        </View>
      </View>
      <View style={styles.card}>
        <Text style={styles.title}>alignItems: flex-start</Text>
        <View style={[styles.container, {alignItems: 'flex-start'}]}>
          <View style={[styles.box, {backgroundColor: 'powderblue'}]} />
          <View style={[styles.box, {backgroundColor: 'skyblue'}]} />
          <View style={[styles.box, {backgroundColor: 'steelblue'}]} />
        </View>
      </View>
      <View style={styles.card}>
        <Text style={styles.title}>alignItems: flex-end</Text>
        <View style={[styles.container, {alignItems: 'flex-end'}]}>
          <View style={[styles.box, {backgroundColor: 'powderblue'}]} />
          <View style={[styles.box, {backgroundColor: 'skyblue'}]} />
          <View style={[styles.box, {backgroundColor: 'steelblue'}]} />
        </View>
      </View>
      <View style={styles.card}>
        <Text style={styles.title}>alignItems: center</Text>
        <View style={[styles.container, {alignItems: 'center'}]}>
          <View style={[styles.box, {backgroundColor: 'powderblue'}]} />
          <View style={[styles.box, {backgroundColor: 'skyblue'}]} />
          <View style={[styles.box, {backgroundColor: 'steelblue'}]} />
        </View>
      </View>
      <View style={styles.card}>
        <Text style={styles.title}>alignItems: baseline</Text>
        <View style={[styles.container, {alignItems: 'baseline'}]}>
          <View style={[styles.box, {backgroundColor: 'powderblue'}]} />
          <View style={[styles.box, {backgroundColor: 'skyblue'}]} />
          <View style={[styles.box, {backgroundColor: 'steelblue'}]} />
        </View>
      </View>
      <View style={styles.card}>
        <Text style={styles.title}>alignItems: baseline vs</Text>
        <Text style={styles.title}>alignSelf: center</Text>
        <View style={[styles.container, {alignItems: 'baseline'}]}>
          <View style={[styles.box, {backgroundColor: 'powderblue'}]} />
          <View
            style={[
              styles.box,
              {backgroundColor: 'skyblue', alignSelf: 'center'},
            ]}
          />
          <View style={[styles.box, {backgroundColor: 'steelblue'}]} />
        </View>
      </View>
    </ScrollView>
  );
};

const styles = StyleSheet.create({
  title: {
    textAlign: 'center',
    fontSize: 24,
    fontWeight: '600',
  },
  card: {
    marginTop: 10,
    backgroundColor: 'oldlace',
  },
  container: {
    marginTop: 10,
  },
  box: {
    minWidth: 50,
    height: 50,
  },
});

export default AlignItems;

 

flexWrap
flexWrap 属性作用于容器上,控制子元素溢出时如何在主轴上排列。默认是强制不换行
import React from 'react';
import {View, Text, StyleSheet} from 'react-native';

const FlexWrap = () => {
  return (
    <View>
      <View style={styles.card}>
        <Text style={styles.title}>flexWrap: nowrap(默认)</Text>
        <View style={[styles.container, {flexWrap: 'nowrap'}]}>
          <View style={[styles.box, {backgroundColor: 'powderblue'}]} />
          <View style={[styles.box, {backgroundColor: 'skyblue'}]} />
          <View style={[styles.box, {backgroundColor: 'steelblue'}]} />
          <View style={[styles.box, {backgroundColor: 'aquamarine'}]} />
          <View style={[styles.box, {backgroundColor: 'cadetblue'}]} />
        </View>
      </View>
      <View style={styles.card}>
        <Text style={styles.title}>flexWrap: wrap</Text>
        <View style={[styles.container, {flexWrap: 'wrap'}]}>
          <View style={[styles.box, {backgroundColor: 'powderblue'}]} />
          <View style={[styles.box, {backgroundColor: 'skyblue'}]} />
          <View style={[styles.box, {backgroundColor: 'steelblue'}]} />
          <View style={[styles.box, {backgroundColor: 'aquamarine'}]} />
          <View style={[styles.box, {backgroundColor: 'cadetblue'}]} />
        </View>
      </View>
      <View style={styles.card}>
        <Text style={styles.title}>flexWrap: wrap-reverse</Text>
        <View style={[styles.container, {flexWrap: 'wrap-reverse'}]}>
          <View style={[styles.box, {backgroundColor: 'powderblue'}]} />
          <View style={[styles.box, {backgroundColor: 'skyblue'}]} />
          <View style={[styles.box, {backgroundColor: 'steelblue'}]} />
          <View style={[styles.box, {backgroundColor: 'aquamarine'}]} />
          <View style={[styles.box, {backgroundColor: 'cadetblue'}]} />
        </View>
      </View>
    </View>
  );
};

const styles = StyleSheet.create({
  title: {
    textAlign: 'center',
    fontSize: 24,
    fontWeight: '600',
  },
  card: {
    marginTop: 10,
    backgroundColor: 'oldlace',
  },
  container: {
    marginTop: 10,
    flexDirection: 'row',
  },
  box: {
    width: 100,
    height: 100,
  },
});

export default FlexWrap;

 

相对定位与绝对定位
一个元素的position类型决定了其在父元素中的位置

position 取值:
relative:(默认值),元素的位置取决于文档流
absolute:元素会脱离正常的文档流
import {StyleSheet, Text, View} from 'react-native';
import React from 'react';

export default function Position() {
  return (
    <View>
      <View style={styles.card}>
        <Text style={styles.title}>position:relative(默认)</Text>
        <View style={[styles.container]}>
          <View style={[styles.box, styles.box1]} />
          <View style={[styles.box, styles.box2]} />
          <View style={[styles.box, styles.box3]} />
        </View>
      </View>
      <View style={styles.card}>
        <Text style={styles.title}>position: absolute</Text>
        <View style={[styles.container]}>
          <View style={[styles.box, styles.box1, styles.pbox]} />
          <View style={[styles.box, styles.box2, styles.pbox]} />
          <View style={[styles.box, styles.box3, styles.pbox]} />
        </View>
      </View>
    </View>
  );
}

const styles = StyleSheet.create({
  card: {
    marginTop: 10,
  },
  title: {
    textAlign: 'center',
    fontSize: 24,
    fontWeight: '600',
    backgroundColor: 'aquamarine',
  },
  container: {
    flexDirection: 'row',
    minHeight: 200,
    backgroundColor: 'oldlace',
  },
  box: {
    width: 100,
    height: 100,
  },
  box1: {
    backgroundColor: 'powderblue',
    top: 25,
    left: 25,
  },
  box2: {
    backgroundColor: 'skyblue',
    top: 50,
    left: 50,
  },
  box3: {
    backgroundColor: 'steelblue',
    top: 75,
    left: 75,
  },
  pbox: {
    position: 'absolute',
  },
});

 

宽度与高度
组件的宽度和高度决定了其在屏幕上显示的尺寸

指定宽高
RN 中的尺寸都是 无单位的,表示的是与设备像素密度无关的逻辑像素点
指定宽高一般用于在不同尺寸的屏幕上都显示成一样的大小
import {View} from 'react-native';
import React from 'react';

export default function Basics() {
  return (
    <View>
      <View style={{width: 50, height: 50, backgroundColor: 'powderblue'}} />
      <View style={{width: 100, height: 100, backgroundColor: 'skyblue'}} />
      <View style={{width: 150, height: 150, backgroundColor: 'steelblue'}} />
    </View>
  );
}

 

弹性(Flex)宽高
在组件中使用 flex 可以使其在可利用的空间中动态地扩张或收缩,一般会使用 flex:1 来指定某个组件扩张以撑满所有剩余的空间

如果有多个并列的子组件使用了 flex:1,则这些子组件会平分父容器的剩余的空间

如果这些并列的子组件的 flex 值不一样,则谁的值更大,谁占据剩余空间的比例就更大

注意:使用 flex 指定宽高的前提是其父容器的尺寸不为零
import {View} from 'react-native';
import React from 'react';

export default function FlexDimensions() {
  return (
    <View style={{height: '100%'}}>
      <View style={{flex: 1, backgroundColor: 'powderblue'}} />
      <View style={{flex: 2, backgroundColor: 'skyblue'}} />
      <View style={{flex: 3, backgroundColor: 'steelblue'}} />
    </View>
  );
}

 

百分比宽高
用法和注意事项同 flex 宽高
import {View} from 'react-native';
import React from 'react';

export default function FlexDimensions() {
  return (
    <View style={{height: '100%'}}>
      <View style={{height: '15%', backgroundColor: 'powderblue'}} />
      <View style={{height: '35%', backgroundColor: 'skyblue'}} />
      <View style={{height: '55%', backgroundColor: 'steelblue'}} />
    </View>
  );
}

 

设备宽高

用法:
获取设备宽度:Dimensions.get('window').width
获取设备高度:Dimensions.get('window).height
import {View, Dimensions, StyleSheet} from 'react-native';
import React from 'react';

export default function DimensionsDemo() {
  return (
    <View style={{flexDirection: 'row'}}>
      {/* 注意看父容器是没有指定宽高的 */}
      <View style={[styles.box, {backgroundColor: 'powderblue'}]} />
      <View style={[styles.box, {backgroundColor: 'skyblue'}]} />
      <View style={[styles.box, {backgroundColor: 'steelblue'}]} />
    </View>
  );
}

const styles = StyleSheet.create({
  box: {
    width: Dimensions.get('window').width / 3, // 三等分设备宽度
    height: 90,
  },
});

 

posted @ 2022-09-01 14:09  rogerwu  阅读(727)  评论(0编辑  收藏  举报