RN 的 StyleSheet
在写系统组件之前,先写下 StyleSheet 样式表的使用。
StyleSheet 是 React Native 特有的。
React 使用内联样式、css 文件、CSS Modules 的形式书写样式。
而 React Native 使用则是使用 StyleSheet 或者内联样式(JavaScript 对象)来定义样式。
如何使用 StyleSheet
import React from 'react';
import { View, StyleSheet } from 'react-native';
const SimpleViewComponent = () => {
return (
<View style={styles.container}>
{/* 这里可以添加其他组件或内容 */}
</View>
);
};
const styles = StyleSheet.create({
container: {
flex: 1, // 占满整个屏幕
justifyContent: 'center', // 垂直居中
alignItems: 'center', // 水平居中
backgroundColor: '#f0f0f0', // 背景颜色
},
});
export default SimpleViewComponent;
StyleSheet 的优势
- 性能优化:
// StyleSheet.create() 会在应用启动时创建一个样式表注册表
const styles = StyleSheet.create({
container: {
// 样式定义会被优化和缓存
}
});
- 类型检查:
// StyleSheet 提供了类型检查,错误的样式属性会在编译时报错
const styles = StyleSheet.create({
container: {
colour: 'red' // ❌ 错误:拼写错误会被检测出来
color: 'red' // ✅ 正确
}
});
- 样式复用:
const styles = StyleSheet.create({
base: {
padding: 10,
backgroundColor: '#fff',
},
primary: {
...StyleSheet.flatten(styles.base), // 扩展基础样式
backgroundColor: 'blue',
}
});
- 特殊方法:
const styles = StyleSheet.create({
container: {
// 绝对填充
...StyleSheet.absoluteFillObject,
// 等同于:
// position: 'absolute',
// left: 0,
// right: 0,
// top: 0,
// bottom: 0
}
});
View
View 组件的 Flex 布局
flexDirection 定义主轴方向,参数值有:
- row
- row-reverse
- column
- column-reverse
flexFrow 和 flex 属性的区别
flex 是一个简写属性,包含了 flexGrow、flexShrink 和 flexBasis 三个属性。
- 空间分配不同
// flex 会同时影响增长和收缩
const styles = StyleSheet.create({
box1: {
flex: 1, // 占用所有可用空间的 1/3
},
box2: {
flex: 2, // 占用所有可用空间的 2/3
},
});
// flexGrow 只影响增长
const styles = StyleSheet.create({
box1: {
flexGrow: 1, // 多余空间分配比例为 1
flexBasis: 100, // 初始大小为 100
},
box2: {
flexGrow: 2, // 多余空间分配比例为 2
flexBasis: 100, // 初始大小为 100
},
});
- 影响初始尺寸
// flex 会重置 flexBasis 为 0
const styles = StyleSheet.create({
box: {
flex: 1,
width: 100, // 这个宽度会被忽略
},
});
// flexGrow 保留初始尺寸
const styles = StyleSheet.create({
box: {
flexGrow: 1,
width: 100, // 这个宽度会被保留作为初始尺寸
},
});
使用建议
- 使用 flex:
- 需要元素完全填充可用空间
- 不关心元素的初始尺寸
- 想要简化代码
- 使用 flexGrow:
- 需要保留元素的初始尺寸
- 只想控制元素如何分配额外空间
- 需要更精确的布局控制
position 绝对定位
- 绝对定位元素相对于最近的 position: 'relative' 的祖先元素定位
- 如果没有父组件设置 position: 'relative',绝对定位的元素会相对于屏幕视口(viewport)进行定位
- 可以理解为:位置是相对于最近的非 static 定位的父元素
1. 父容器关系:
// 绝对定位元素相对于最近的 position: 'relative' 的祖先元素定位
const styles = StyleSheet.create({
parent: {
position: 'relative', // 重要!
// ...
},
child: {
position: 'absolute',
// ...
},
});
2. 性能考虑
// 避免过多使用绝对定位,可能影响性能
// 优先使用 Flex 布局
const styles = StyleSheet.create({
container: {
flex: 1,
justifyContent: 'center',
alignItems: 'center',
},
});
- 跨平台兼容性:
// 某些定位值在不同平台可能表现不同
const styles = StyleSheet.create({
element: {
position: 'absolute',
...Platform.select({
ios: {
top: 20,
},
android: {
top: 0,
},
}),
},
});
View 组件的 onLayout 属性
onLayout 是 React Native View 组件的一个重要属性,它在组件布局完成或布局发生变化时触发。这个事件可以让我们获取组件的尺寸和位置信息。
初始化时机:可能在组件挂载后立即触发,但也可能需要等待一段时间
const Component = () => {
useEffect(() => {
// onLayout 可能在组件挂载后立即触发
// 但也可能需要等待一段时间
}, []);
return (
<View
onLayout={({ nativeEvent }) => {
// 确保在使用布局信息前已经获取到有效值
if (nativeEvent.layout.width > 0) {
// 处理布局
}
}}
>
{/* 内容 */}
</View>
);
};
例子:
import React, {useState} from 'react';
import {View, Text, StyleSheet} from 'react-native';
export default () => {
const [dimensions, setDimensions] = useState({
width: 0,
height: 0,
x: 0,
y: 0,
});
return (
<View
style={styles.container}
onLayout={event => {
const {width, height, x, y} = event.nativeEvent.layout;
setDimensions({width, height, x, y});
}}>
<Text>
宽度: {dimensions.width}
{'\n'}
高度: {dimensions.height}
{'\n'}
X坐标: {dimensions.x}
{'\n'}
Y坐标: {dimensions.y}
</Text>
</View>
);
};
const styles = StyleSheet.create({
container: {
padding: 20,
margin: 10,
backgroundColor: 'red',
},
});
setNativeProps
setNativeProps 是 React Native 提供的一个直接操作原生视图的方法,它允许我们在不触发 React 重新渲染的情况下直接修改原生视图的属性。这对于需要频繁更新的动画或者实时更新非常有用。
例子:
import React, { useRef, useEffect } from 'react';
import { View, Animated } from 'react-native';
const AnimationExample = () => {
const viewRef = useRef(null);
useEffect(() => {
let position = 0;
const animate = () => {
position += 1;
viewRef.current?.setNativeProps({
style: {
transform: [{ translateX: position % 100 }]
}
});
requestAnimationFrame(animate);
};
requestAnimationFrame(animate);
}, []);
return (
<View
ref={viewRef}
style={styles.animatedBox}
/>
);
};
使用限制
const Component = () => {
const viewRef = useRef<View>(null);
// ✅ 可以更新的属性
viewRef.current?.setNativeProps({
style: {
opacity: 0.5,
transform: [{ scale: 1.1 }],
backgroundColor: 'red',
}
});
// ❌ 不能更新的属性
viewRef.current?.setNativeProps({
children: <Text>新内容</Text>, // 错误:不能更新子组件
onPress: () => {}, // 错误:不能更新事件处理器
});
};
Text
<Text
style={{
// 文本特有样式
fontSize: 16,
fontWeight: 'bold',
lineHeight: 24,
textAlign: 'center',
textDecorationLine: 'underline',
// 文本特有属性
numberOfLines={2}
ellipsizeMode="tail"
}}
>
文字内容
</Text>
Text 的 numberOfLines 属性
numberOfLines 是 Text 组件的一个重要属性,用于限制文本显示的行数。当文本内容超过指定的行数时,会自动截断并显示省略号。
属性值指定显示的文本行数。
Text 的 ellipsizeMode 属性
ellipsizeMode 是 Text 组件的一个属性,用于控制文本被截断时省略号的显示位置。
它有四个可选值:'head'、'middle'、'tail' 和 'clip'。
- 默认值是 'tail',在尾部显示省略号
- head,在头部显示省略号
- middle 在中部显示省略号
- clip,裁剪掉文字
例子:
import React from 'react';
import { View, Text, StyleSheet } from 'react-native';
const EllipsisExample = () => {
const longText = "这是一段非常长的文本内容,用来演示不同的省略模式效果";
return (
<View style={styles.container}>
{/* 在开头显示省略号 */}
<Text
numberOfLines={1}
ellipsizeMode="head"
style={styles.text}
>
{longText}
</Text>
{/* 在中间显示省略号 */}
<Text
numberOfLines={1}
ellipsizeMode="middle"
style={styles.text}
>
{longText}
</Text>
{/* 在末尾显示省略号(默认) */}
<Text
numberOfLines={1}
ellipsizeMode="tail"
style={styles.text}
>
{longText}
</Text>
{/* 直接裁剪文本,不显示省略号 */}
<Text
numberOfLines={1}
ellipsizeMode="clip"
style={styles.text}
>
{longText}
</Text>
</View>
);
};
const styles = StyleSheet.create({
container: {
padding: 20,
},
text: {
fontSize: 16,
marginBottom: 10,
},
});
Text 的 selectable、selectionColor 属性
- selectable 文本是否可选中
- selectionColor 选中文本的颜色
import React from 'react';
import {View, Text, StyleSheet} from 'react-native';
export default () => {
return (
<View style={styles.container}>
{/* 自定义选择颜色 */}
<Text
selectable={true}
selectionColor="#AEAEAE"
style={styles.coloredText}>
这段文本被选中时会显示橙色背景
</Text>
</View>
);
};
const styles = StyleSheet.create({
container: {
padding: 20,
},
coloredText: {
fontSize: 16,
lineHeight: 24,
},
});
Text 的 onPress、onLongPress 属性
onPress 和 onLongPress 是 Text 组件的点击事件处理属性,用于响应用户的点击和长按操作。
例子:
import React, { useState } from 'react';
import { Text, View, StyleSheet } from 'react-native';
const TextPressExample = () => {
const [pressCount, setPressCount] = useState(0);
const [lastPress, setLastPress] = useState('无');
return (
<View style={styles.container}>
<Text
style={styles.text}
onPress={() => {
setPressCount(prev => prev + 1);
setLastPress('点击');
}}
onLongPress={() => {
setLastPress('长按');
}}
>
点击或长按这段文字
</Text>
<Text>点击次数: {pressCount}</Text>
<Text>最后操作: {lastPress}</Text>
</View>
);
};
const styles = StyleSheet.create({
container: {
padding: 20,
},
text: {
fontSize: 16,
color: 'blue',
padding: 10,
},
});
点击两次,最后长按效果:
Text 的 allowFontScaling 属性
allowFontScaling 是 Text 组件的一个属性,用于控制文本是否随系统字体大小设置而缩放。这对于创建响应式和无障碍的应用程序非常重要。
<View style={styles.container}>
{/* 允许字体缩放(默认行为) */}
<Text>
这段文字会随系统字体大小变化而缩放
</Text>
{/* 禁止字体缩放 */}
<Text allowFontScaling={false}>
这段文字大小保持固定
</Text>
</View>
Text 的 maxFontSizeMultiplier 属性
const MaxScaleExample = () => {
return (
<View>
<Text
allowFontScaling={true}
maxFontSizeMultiplier={1.5} // 最大放大到 1.5 倍
style={styles.text}
>
这段文字最多放大到 1.5 倍
</Text>
</View>
);
};
Text 的 textAlign、textAlignVertical 属性
textAlign 和 textAlignVertical 是 Text 组件的对齐方式属性,分别控制文本的水平和垂直对齐。
Text 装饰属性
-
textDecorationLine:定义装饰线的位置(下划线、删除线、上划线)
-
textDecorationStyle:定义装饰线的样式(实线、虚线、点线、双线)
Text 的文字阴影
-
textShadowColor,控制阴影的颜色
-
textShadowOffset,控制阴影的偏移位置,包含 width(水平偏移)和 height(垂直偏移)
-
textShadowRadius,控制阴影的模糊半径,值越大阴影越模糊
例子:
const styles = StyleSheet.create({
container: {
padding: 20,
},
// 基本阴影
basicShadow: {
fontSize: 24,
marginVertical: 10,
textShadowColor: 'rgba(0, 0, 0, 0.75)',
textShadowOffset: {width: 2, height: 2},
textShadowRadius: 1,
},
// 模糊阴影
blurredShadow: {
fontSize: 24,
marginVertical: 10,
textShadowColor: 'rgba(0, 0, 0, 0.5)',
textShadowOffset: {width: 3, height: 3},
textShadowRadius: 5,
},
// 多重阴影
multipleShadow: {
fontSize: 24,
marginVertical: 10,
color: '#fff',
textShadowColor: '#000',
textShadowOffset: {width: -1, height: 1},
textShadowRadius: 10,
},
// 发光效果
glowEffect: {
fontSize: 24,
marginVertical: 10,
color: '#fff',
textShadowColor: '#0066ff',
textShadowOffset: {width: 0, height: 0},
textShadowRadius: 15,
},
});
Text 的无障碍支持
const AccessibleText = ({ text }) => {
return (
<Text
allowFontScaling={true}
accessible={true}
accessibilityLabel={text}
style={styles.text}
>
{text}
</Text>
);
};
RN 的 View 和 Text 组件的区别
1. 基本定位和用途
View 组件:
// View 是一个容器组件,类似于 HTML 中的 div
<View style={styles.container}>
<View style={styles.box}>
<Text>内容</Text>
</View>
</View>
Text 组件:
// Text 专门用于显示文本内容,类似于 HTML 中的 span 或 p
<Text style={styles.text}>
这是一段文字
<Text style={styles.highlight}>高亮文字</Text>
</Text>
2. 主要区别
- 嵌套规则
// ✅ 正确:Text 可以嵌套在 View 中
<View>
<Text>文字内容</Text>
</View>
// ✅ 正确:Text 可以嵌套 Text
<Text>
外层文字
<Text>内层文字</Text>
</Text>
// ❌ 错误:View 不能直接嵌套在 Text 中
<Text>
文字
<View> {/* 这样做会报错 */}
<Text>更多文字</Text>
</View>
</Text>
- 样式继承
// Text 组件有样式继承
<Text style={{ color: 'red', fontSize: 16 }}>
父级文字
<Text>
子级文字 {/* 会继承父级的红色和字号 */}
</Text>
</Text>
// View 组件没有样式继承
<View style={{ backgroundColor: 'red' }}>
<View> {/* 不会继承父级的背景色 */}
</View>
</View>
- 特有属性
<View
style={{
// 布局相关
flex: 1,
flexDirection: 'row', // row-reverse | column | column-reverse
// 边框相关
borderRadius: 10,
borderWidth: 1,
// 背景
backgroundColor: '#fff',
// 阴影(iOS)
shadowColor: '#000',
shadowOffset: { width: 0, height: 2 },
shadowOpacity: 0.25,
// 阴影(Android)
elevation: 5,
}}
/>
<Text
style={{
// 文本特有样式
fontSize: 16,
fontWeight: 'bold',
lineHeight: 24,
textAlign: 'center',
textDecorationLine: 'underline',
// 文本特有属性
numberOfLines={2}
ellipsizeMode="tail"
}}
>
文字内容
</Text>
3. 常见使用场景
- View 当作布局容器使用
<View style={styles.container}>
<View style={styles.header}>
<Text style={styles.title}>标题</Text>
</View>
<View style={styles.content}>
{/* 其他内容 */}
</View>
</View>
- Text 用来显示文本
<Text style={styles.paragraph}>
这是一段普通文字
<Text style={styles.bold}>加粗文字</Text>
<Text style={styles.italic}>斜体文字</Text>
{'\n'}
<Text style={styles.link}>链接文字</Text>
</Text>
4. 注意事项
- 所有文本内容必须包含在 Text 组件中
- View 中不能直接放置文本内容
- 避免过深的 View 嵌套
- 合理使用 Text 的样式继承特性