第2章:核心组件与布局
📖 本章概述
在这一章中,我们将深入学习 React Native 的核心组件和布局系统。这些是构建移动应用界面的基础,掌握它们对后续开发至关重要。
🧱 基础组件
View - 容器组件
View
是最基础的组件,类似于 HTML 中的 div
,用作其他组件的容器。
typescript
import React from 'react';
import {View, StyleSheet} from 'react-native';
const ViewExample: React.FC = () => {
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,
padding: 20,
backgroundColor: '#f0f0f0',
},
box1: {
width: 100,
height: 100,
backgroundColor: '#ff6b6b',
marginBottom: 10,
},
box2: {
width: 150,
height: 100,
backgroundColor: '#4ecdc4',
marginBottom: 10,
},
box3: {
width: 120,
height: 100,
backgroundColor: '#45b7d1',
},
});
Text - 文本组件
Text
组件用于显示文本,支持嵌套和样式设置。
typescript
import React from 'react';
import {View, Text, StyleSheet} from 'react-native';
const TextExample: React.FC = () => {
return (
<View style={styles.container}>
{/* 基础文本 */}
<Text style={styles.title}>这是标题</Text>
{/* 嵌套文本 */}
<Text style={styles.paragraph}>
这是一段普通文本,
<Text style={styles.bold}>这部分是粗体</Text>
,这里还有
<Text style={styles.italic}>斜体文本</Text>
。
</Text>
{/* 可选择文本 */}
<Text selectable style={styles.selectable}>
这段文本可以被选择和复制
</Text>
{/* 限制行数 */}
<Text numberOfLines={2} style={styles.multiline}>
这是一段很长的文本,用来演示如何限制显示行数。
当文本超过指定行数时,会自动截断并显示省略号。
这样可以保持界面的整洁。
</Text>
</View>
);
};
const styles = StyleSheet.create({
container: {
flex: 1,
padding: 20,
backgroundColor: '#fff',
},
title: {
fontSize: 24,
fontWeight: 'bold',
color: '#333',
marginBottom: 15,
textAlign: 'center',
},
paragraph: {
fontSize: 16,
lineHeight: 24,
color: '#666',
marginBottom: 15,
},
bold: {
fontWeight: 'bold',
color: '#333',
},
italic: {
fontStyle: 'italic',
color: '#007AFF',
},
selectable: {
fontSize: 14,
color: '#999',
backgroundColor: '#f8f8f8',
padding: 10,
borderRadius: 5,
marginBottom: 15,
},
multiline: {
fontSize: 14,
color: '#666',
backgroundColor: '#f0f0f0',
padding: 10,
borderRadius: 5,
},
});
Image - 图片组件
Image
组件用于显示图片,支持本地图片和网络图片。
typescript
import React from 'react';
import {View, Image, StyleSheet, Dimensions} from 'react-native';
const {width} = Dimensions.get('window');
const ImageExample: React.FC = () => {
return (
<View style={styles.container}>
{/* 本地图片 */}
<Image
source={require('./assets/local-image.png')}
style={styles.localImage}
/>
{/* 网络图片 */}
<Image
source={{
uri: 'https://picsum.photos/300/200',
}}
style={styles.networkImage}
resizeMode="cover"
/>
{/* 带加载指示器的网络图片 */}
<Image
source={{
uri: 'https://picsum.photos/300/150',
}}
style={styles.imageWithIndicator}
loadingIndicatorSource={require('./assets/loading.gif')}
onLoad={() => console.log('图片加载完成')}
onError={() => console.log('图片加载失败')}
/>
</View>
);
};
const styles = StyleSheet.create({
container: {
flex: 1,
padding: 20,
alignItems: 'center',
},
localImage: {
width: 100,
height: 100,
borderRadius: 50,
marginBottom: 20,
},
networkImage: {
width: width - 40,
height: 200,
borderRadius: 10,
marginBottom: 20,
},
imageWithIndicator: {
width: width - 40,
height: 150,
borderRadius: 10,
},
});
🎯 交互组件
Button - 按钮组件
React Native 提供了基础的 Button
组件,但通常我们使用 TouchableOpacity
来创建自定义按钮。
typescript
import React from 'react';
import {
View,
Text,
Button,
TouchableOpacity,
TouchableHighlight,
StyleSheet,
Alert,
} from 'react-native';
const ButtonExample: React.FC = () => {
const handlePress = (buttonName: string) => {
Alert.alert('按钮点击', `你点击了${buttonName}按钮`);
};
return (
<View style={styles.container}>
{/* 基础按钮 */}
<Button
title="基础按钮"
onPress={() => handlePress('基础')}
color="#007AFF"
/>
{/* TouchableOpacity 自定义按钮 */}
<TouchableOpacity
style={styles.customButton}
onPress={() => handlePress('自定义')}
activeOpacity={0.7}
>
<Text style={styles.buttonText}>自定义按钮</Text>
</TouchableOpacity>
{/* TouchableHighlight 按钮 */}
<TouchableHighlight
style={styles.highlightButton}
onPress={() => handlePress('高亮')}
underlayColor="#0056b3"
>
<Text style={styles.buttonText}>高亮按钮</Text>
</TouchableHighlight>
{/* 禁用状态按钮 */}
<TouchableOpacity
style={[styles.customButton, styles.disabledButton]}
disabled={true}
>
<Text style={[styles.buttonText, styles.disabledText]}>
禁用按钮
</Text>
</TouchableOpacity>
</View>
);
};
const styles = StyleSheet.create({
container: {
flex: 1,
padding: 20,
justifyContent: 'center',
},
customButton: {
backgroundColor: '#007AFF',
paddingVertical: 12,
paddingHorizontal: 24,
borderRadius: 8,
marginVertical: 10,
alignItems: 'center',
},
highlightButton: {
backgroundColor: '#007AFF',
paddingVertical: 12,
paddingHorizontal: 24,
borderRadius: 8,
marginVertical: 10,
alignItems: 'center',
},
buttonText: {
color: '#fff',
fontSize: 16,
fontWeight: 'bold',
},
disabledButton: {
backgroundColor: '#ccc',
},
disabledText: {
color: '#999',
},
});
TextInput - 输入框组件
TextInput
用于文本输入,支持多种输入类型和验证。
typescript
import React, {useState} from 'react';
import {
View,
Text,
TextInput,
StyleSheet,
KeyboardAvoidingView,
Platform,
} from 'react-native';
const TextInputExample: React.FC = () => {
const [name, setName] = useState('');
const [email, setEmail] = useState('');
const [password, setPassword] = useState('');
const [description, setDescription] = useState('');
return (
<KeyboardAvoidingView
style={styles.container}
behavior={Platform.OS === 'ios' ? 'padding' : 'height'}
>
<Text style={styles.title}>用户信息表单</Text>
{/* 基础输入框 */}
<View style={styles.inputContainer}>
<Text style={styles.label}>姓名</Text>
<TextInput
style={styles.input}
value={name}
onChangeText={setName}
placeholder="请输入姓名"
placeholderTextColor="#999"
/>
</View>
{/* 邮箱输入框 */}
<View style={styles.inputContainer}>
<Text style={styles.label}>邮箱</Text>
<TextInput
style={styles.input}
value={email}
onChangeText={setEmail}
placeholder="请输入邮箱"
placeholderTextColor="#999"
keyboardType="email-address"
autoCapitalize="none"
autoCorrect={false}
/>
</View>
{/* 密码输入框 */}
<View style={styles.inputContainer}>
<Text style={styles.label}>密码</Text>
<TextInput
style={styles.input}
value={password}
onChangeText={setPassword}
placeholder="请输入密码"
placeholderTextColor="#999"
secureTextEntry={true}
autoCapitalize="none"
/>
</View>
{/* 多行输入框 */}
<View style={styles.inputContainer}>
<Text style={styles.label}>个人描述</Text>
<TextInput
style={[styles.input, styles.multilineInput]}
value={description}
onChangeText={setDescription}
placeholder="请输入个人描述"
placeholderTextColor="#999"
multiline={true}
numberOfLines={4}
textAlignVertical="top"
/>
</View>
</KeyboardAvoidingView>
);
};
const styles = StyleSheet.create({
container: {
flex: 1,
padding: 20,
backgroundColor: '#fff',
},
title: {
fontSize: 24,
fontWeight: 'bold',
color: '#333',
marginBottom: 30,
textAlign: 'center',
},
inputContainer: {
marginBottom: 20,
},
label: {
fontSize: 16,
fontWeight: '500',
color: '#333',
marginBottom: 8,
},
input: {
borderWidth: 1,
borderColor: '#ddd',
borderRadius: 8,
paddingHorizontal: 12,
paddingVertical: 10,
fontSize: 16,
backgroundColor: '#f9f9f9',
},
multilineInput: {
height: 100,
textAlignVertical: 'top',
},
});
📋 列表组件
ScrollView - 滚动视图
ScrollView
用于创建可滚动的内容区域。
typescript
import React from 'react';
import {ScrollView, View, Text, StyleSheet} from 'react-native';
const ScrollViewExample: React.FC = () => {
const items = Array.from({length: 20}, (_, i) => `项目 ${i + 1}`);
return (
<ScrollView
style={styles.container}
showsVerticalScrollIndicator={false}
bounces={true}
>
<Text style={styles.title}>滚动视图示例</Text>
{items.map((item, index) => (
<View key={index} style={styles.item}>
<Text style={styles.itemText}>{item}</Text>
</View>
))}
<View style={styles.footer}>
<Text style={styles.footerText}>已到达底部</Text>
</View>
</ScrollView>
);
};
const styles = StyleSheet.create({
container: {
flex: 1,
backgroundColor: '#fff',
},
title: {
fontSize: 24,
fontWeight: 'bold',
color: '#333',
textAlign: 'center',
paddingVertical: 20,
},
item: {
backgroundColor: '#f8f8f8',
padding: 15,
marginHorizontal: 20,
marginVertical: 5,
borderRadius: 8,
borderLeftWidth: 4,
borderLeftColor: '#007AFF',
},
itemText: {
fontSize: 16,
color: '#333',
},
footer: {
padding: 20,
alignItems: 'center',
},
footerText: {
fontSize: 14,
color: '#999',
},
});
FlatList - 高性能列表
FlatList
是处理大量数据的高性能列表组件。
typescript
import React, {useState} from 'react';
import {
View,
Text,
FlatList,
TouchableOpacity,
StyleSheet,
RefreshControl,
} from 'react-native';
interface ListItem {
id: string;
title: string;
description: string;
}
const FlatListExample: React.FC = () => {
const [data, setData] = useState<ListItem[]>(
Array.from({length: 50}, (_, i) => ({
id: i.toString(),
title: `标题 ${i + 1}`,
description: `这是第 ${i + 1} 项的描述内容`,
}))
);
const [refreshing, setRefreshing] = useState(false);
const onRefresh = () => {
setRefreshing(true);
// 模拟网络请求
setTimeout(() => {
setRefreshing(false);
}, 2000);
};
const renderItem = ({item}: {item: ListItem}) => (
<TouchableOpacity style={styles.item}>
<Text style={styles.itemTitle}>{item.title}</Text>
<Text style={styles.itemDescription}>{item.description}</Text>
</TouchableOpacity>
);
const renderSeparator = () => <View style={styles.separator} />;
const renderHeader = () => (
<View style={styles.header}>
<Text style={styles.headerText}>列表头部</Text>
</View>
);
const renderFooter = () => (
<View style={styles.footer}>
<Text style={styles.footerText}>列表底部</Text>
</View>
);
return (
<FlatList
data={data}
renderItem={renderItem}
keyExtractor={item => item.id}
ItemSeparatorComponent={renderSeparator}
ListHeaderComponent={renderHeader}
ListFooterComponent={renderFooter}
refreshControl={
<RefreshControl refreshing={refreshing} onRefresh={onRefresh} />
}
showsVerticalScrollIndicator={false}
/>
);
};
const styles = StyleSheet.create({
item: {
backgroundColor: '#fff',
padding: 15,
marginHorizontal: 10,
},
itemTitle: {
fontSize: 16,
fontWeight: 'bold',
color: '#333',
marginBottom: 5,
},
itemDescription: {
fontSize: 14,
color: '#666',
},
separator: {
height: 1,
backgroundColor: '#eee',
marginHorizontal: 10,
},
header: {
backgroundColor: '#007AFF',
padding: 15,
alignItems: 'center',
},
headerText: {
fontSize: 18,
fontWeight: 'bold',
color: '#fff',
},
footer: {
padding: 15,
alignItems: 'center',
backgroundColor: '#f8f8f8',
},
footerText: {
fontSize: 14,
color: '#999',
},
});
📐 Flexbox 布局系统
React Native 使用 Flexbox 作为主要的布局系统,但与 CSS 有一些差异。
基本概念
typescript
import React from 'react';
import {View, Text, StyleSheet} from 'react-native';
const FlexboxBasics: React.FC = () => {
return (
<View style={styles.container}>
{/* 主轴方向 */}
<View style={styles.section}>
<Text style={styles.sectionTitle}>flexDirection: 'row'</Text>
<View style={styles.rowContainer}>
<View style={[styles.box, {backgroundColor: '#ff6b6b'}]} />
<View style={[styles.box, {backgroundColor: '#4ecdc4'}]} />
<View style={[styles.box, {backgroundColor: '#45b7d1'}]} />
</View>
</View>
<View style={styles.section}>
<Text style={styles.sectionTitle}>flexDirection: 'column'</Text>
<View style={styles.columnContainer}>
<View style={[styles.box, {backgroundColor: '#ff6b6b'}]} />
<View style={[styles.box, {backgroundColor: '#4ecdc4'}]} />
<View style={[styles.box, {backgroundColor: '#45b7d1'}]} />
</View>
</View>
</View>
);
};
const styles = StyleSheet.create({
container: {
flex: 1,
padding: 20,
backgroundColor: '#fff',
},
section: {
marginBottom: 30,
},
sectionTitle: {
fontSize: 16,
fontWeight: 'bold',
marginBottom: 10,
color: '#333',
},
rowContainer: {
flexDirection: 'row',
height: 60,
backgroundColor: '#f0f0f0',
padding: 10,
},
columnContainer: {
flexDirection: 'column',
height: 200,
backgroundColor: '#f0f0f0',
padding: 10,
},
box: {
width: 50,
height: 50,
margin: 5,
},
});
对齐方式
typescript
const AlignmentExample: React.FC = () => {
return (
<View style={styles.container}>
{/* justifyContent 示例 */}
<View style={styles.section}>
<Text style={styles.sectionTitle}>justifyContent</Text>
<Text style={styles.subTitle}>flex-start</Text>
<View style={[styles.demoContainer, {justifyContent: 'flex-start'}]}>
<View style={styles.smallBox} />
<View style={styles.smallBox} />
<View style={styles.smallBox} />
</View>
<Text style={styles.subTitle}>center</Text>
<View style={[styles.demoContainer, {justifyContent: 'center'}]}>
<View style={styles.smallBox} />
<View style={styles.smallBox} />
<View style={styles.smallBox} />
</View>
<Text style={styles.subTitle}>space-between</Text>
<View style={[styles.demoContainer, {justifyContent: 'space-between'}]}>
<View style={styles.smallBox} />
<View style={styles.smallBox} />
<View style={styles.smallBox} />
</View>
</View>
{/* alignItems 示例 */}
<View style={styles.section}>
<Text style={styles.sectionTitle}>alignItems</Text>
<Text style={styles.subTitle}>flex-start</Text>
<View style={[styles.demoContainer, {alignItems: 'flex-start'}]}>
<View style={[styles.smallBox, {height: 30}]} />
<View style={[styles.smallBox, {height: 50}]} />
<View style={[styles.smallBox, {height: 40}]} />
</View>
<Text style={styles.subTitle}>center</Text>
<View style={[styles.demoContainer, {alignItems: 'center'}]}>
<View style={[styles.smallBox, {height: 30}]} />
<View style={[styles.smallBox, {height: 50}]} />
<View style={[styles.smallBox, {height: 40}]} />
</View>
</View>
</View>
);
};
const alignmentStyles = StyleSheet.create({
container: {
flex: 1,
padding: 20,
backgroundColor: '#fff',
},
section: {
marginBottom: 20,
},
sectionTitle: {
fontSize: 18,
fontWeight: 'bold',
marginBottom: 15,
color: '#333',
},
subTitle: {
fontSize: 14,
fontWeight: '500',
marginBottom: 5,
color: '#666',
},
demoContainer: {
flexDirection: 'row',
height: 60,
backgroundColor: '#f0f0f0',
marginBottom: 10,
padding: 5,
},
smallBox: {
width: 40,
height: 40,
backgroundColor: '#007AFF',
margin: 2,
},
});
Flex 属性
typescript
const FlexPropertiesExample: React.FC = () => {
return (
<View style={flexStyles.container}>
<Text style={flexStyles.title}>Flex 属性示例</Text>
{/* flex: 1 示例 */}
<View style={flexStyles.section}>
<Text style={flexStyles.sectionTitle}>flex: 1</Text>
<View style={flexStyles.flexContainer}>
<View style={[flexStyles.flexBox, {flex: 1, backgroundColor: '#ff6b6b'}]}>
<Text style={flexStyles.boxText}>flex: 1</Text>
</View>
<View style={[flexStyles.flexBox, {flex: 1, backgroundColor: '#4ecdc4'}]}>
<Text style={flexStyles.boxText}>flex: 1</Text>
</View>
</View>
</View>
{/* 不同 flex 值 */}
<View style={flexStyles.section}>
<Text style={flexStyles.sectionTitle}>不同 flex 值</Text>
<View style={flexStyles.flexContainer}>
<View style={[flexStyles.flexBox, {flex: 1, backgroundColor: '#ff6b6b'}]}>
<Text style={flexStyles.boxText}>flex: 1</Text>
</View>
<View style={[flexStyles.flexBox, {flex: 2, backgroundColor: '#4ecdc4'}]}>
<Text style={flexStyles.boxText}>flex: 2</Text>
</View>
<View style={[flexStyles.flexBox, {flex: 1, backgroundColor: '#45b7d1'}]}>
<Text style={flexStyles.boxText}>flex: 1</Text>
</View>
</View>
</View>
{/* flexGrow, flexShrink, flexBasis */}
<View style={flexStyles.section}>
<Text style={flexStyles.sectionTitle}>flexGrow & flexShrink</Text>
<View style={flexStyles.flexContainer}>
<View style={[flexStyles.flexBox, {
flexGrow: 1,
flexShrink: 1,
flexBasis: 100,
backgroundColor: '#ff6b6b'
}]}>
<Text style={flexStyles.boxText}>grow: 1</Text>
</View>
<View style={[flexStyles.flexBox, {
flexGrow: 2,
flexShrink: 1,
flexBasis: 100,
backgroundColor: '#4ecdc4'
}]}>
<Text style={flexStyles.boxText}>grow: 2</Text>
</View>
</View>
</View>
</View>
);
};
const flexStyles = StyleSheet.create({
container: {
flex: 1,
padding: 20,
backgroundColor: '#fff',
},
title: {
fontSize: 24,
fontWeight: 'bold',
textAlign: 'center',
marginBottom: 20,
color: '#333',
},
section: {
marginBottom: 25,
},
sectionTitle: {
fontSize: 16,
fontWeight: 'bold',
marginBottom: 10,
color: '#333',
},
flexContainer: {
flexDirection: 'row',
height: 80,
backgroundColor: '#f8f8f8',
padding: 5,
},
flexBox: {
justifyContent: 'center',
alignItems: 'center',
margin: 2,
borderRadius: 5,
},
boxText: {
color: '#fff',
fontSize: 12,
fontWeight: 'bold',
textAlign: 'center',
},
});
🎨 样式系统深入
样式继承和组合
typescript
const StyleExample: React.FC = () => {
return (
<View style={styleExampleStyles.container}>
{/* 基础样式 */}
<Text style={styleExampleStyles.baseText}>基础文本样式</Text>
{/* 样式组合 */}
<Text style={[styleExampleStyles.baseText, styleExampleStyles.largeText]}>
组合样式:基础 + 大字体
</Text>
{/* 条件样式 */}
<Text style={[
styleExampleStyles.baseText,
true && styleExampleStyles.successText
]}>
条件样式:成功状态
</Text>
{/* 动态样式 */}
<View style={[
styleExampleStyles.box,
{backgroundColor: '#' + Math.floor(Math.random()*16777215).toString(16)}
]}>
<Text style={styleExampleStyles.boxText}>动态背景色</Text>
</View>
</View>
);
};
const styleExampleStyles = StyleSheet.create({
container: {
flex: 1,
padding: 20,
backgroundColor: '#fff',
},
baseText: {
fontSize: 16,
color: '#333',
marginBottom: 10,
},
largeText: {
fontSize: 20,
fontWeight: 'bold',
},
successText: {
color: '#28a745',
fontWeight: '500',
},
box: {
width: 200,
height: 100,
justifyContent: 'center',
alignItems: 'center',
borderRadius: 10,
marginTop: 20,
},
boxText: {
color: '#fff',
fontSize: 16,
fontWeight: 'bold',
},
});
响应式设计
typescript
import {Dimensions, PixelRatio} from 'react-native';
const {width, height} = Dimensions.get('window');
const scale = width / 375; // 基于 iPhone X 的设计稿
// 响应式字体大小
const normalize = (size: number) => {
const newSize = size * scale;
return Math.round(PixelRatio.roundToNearestPixel(newSize));
};
const ResponsiveExample: React.FC = () => {
const isTablet = width >= 768;
return (
<View style={responsiveStyles.container}>
<Text style={[
responsiveStyles.title,
{fontSize: normalize(isTablet ? 28 : 24)}
]}>
响应式标题
</Text>
<View style={[
responsiveStyles.content,
{
flexDirection: isTablet ? 'row' : 'column',
padding: isTablet ? 30 : 20,
}
]}>
<View style={[
responsiveStyles.card,
{
width: isTablet ? '48%' : '100%',
marginBottom: isTablet ? 0 : 20,
}
]}>
<Text style={responsiveStyles.cardText}>卡片 1</Text>
</View>
<View style={[
responsiveStyles.card,
{
width: isTablet ? '48%' : '100%',
marginLeft: isTablet ? '4%' : 0,
}
]}>
<Text style={responsiveStyles.cardText}>卡片 2</Text>
</View>
</View>
</View>
);
};
const responsiveStyles = StyleSheet.create({
container: {
flex: 1,
backgroundColor: '#fff',
},
title: {
fontWeight: 'bold',
textAlign: 'center',
color: '#333',
marginVertical: 20,
},
content: {
flex: 1,
justifyContent: 'space-between',
},
card: {
backgroundColor: '#f8f9fa',
padding: 20,
borderRadius: 10,
borderWidth: 1,
borderColor: '#dee2e6',
justifyContent: 'center',
alignItems: 'center',
minHeight: 150,
},
cardText: {
fontSize: normalize(16),
color: '#333',
fontWeight: '500',
},
});
🎯 实践项目:个人资料卡片
让我们创建一个完整的个人资料卡片组件,综合运用本章学到的知识:
typescript
import React, {useState} from 'react';
import {
View,
Text,
Image,
TouchableOpacity,
ScrollView,
StyleSheet,
Dimensions,
} from 'react-native';
const {width} = Dimensions.get('window');
interface Skill {
name: string;
level: number;
}
interface ProfileData {
name: string;
title: string;
avatar: string;
bio: string;
location: string;
email: string;
skills: Skill[];
stats: {
projects: number;
followers: number;
following: number;
};
}
const ProfileCard: React.FC = () => {
const [activeTab, setActiveTab] = useState<'about' | 'skills'>('about');
const profileData: ProfileData = {
name: '张小明',
title: 'React Native 开发工程师',
avatar: 'https://picsum.photos/150/150?random=1',
bio: '热爱技术的移动应用开发者,专注于 React Native 和跨平台开发。喜欢分享技术经验,持续学习新技术。',
location: '北京,中国',
email: 'zhangxiaoming@example.com',
skills: [
{name: 'React Native', level: 90},
{name: 'TypeScript', level: 85},
{name: 'React', level: 88},
{name: 'Node.js', level: 75},
{name: 'Flutter', level: 60},
],
stats: {
projects: 24,
followers: 1205,
following: 186,
},
};
const renderSkillBar = (skill: Skill) => (
<View key={skill.name} style={profileStyles.skillItem}>
<View style={profileStyles.skillHeader}>
<Text style={profileStyles.skillName}>{skill.name}</Text>
<Text style={profileStyles.skillLevel}>{skill.level}%</Text>
</View>
<View style={profileStyles.skillBarContainer}>
<View
style={[
profileStyles.skillBar,
{width: `${skill.level}%`}
]}
/>
</View>
</View>
);
return (
<ScrollView style={profileStyles.container}>
{/* 头部信息 */}
<View style={profileStyles.header}>
<Image source={{uri: profileData.avatar}} style={profileStyles.avatar} />
<Text style={profileStyles.name}>{profileData.name}</Text>
<Text style={profileStyles.title}>{profileData.title}</Text>
<Text style={profileStyles.location}>{profileData.location}</Text>
</View>
{/* 统计信息 */}
<View style={profileStyles.statsContainer}>
<View style={profileStyles.statItem}>
<Text style={profileStyles.statNumber}>{profileData.stats.projects}</Text>
<Text style={profileStyles.statLabel}>项目</Text>
</View>
<View style={profileStyles.statDivider} />
<View style={profileStyles.statItem}>
<Text style={profileStyles.statNumber}>{profileData.stats.followers}</Text>
<Text style={profileStyles.statLabel}>关注者</Text>
</View>
<View style={profileStyles.statDivider} />
<View style={profileStyles.statItem}>
<Text style={profileStyles.statNumber}>{profileData.stats.following}</Text>
<Text style={profileStyles.statLabel}>关注中</Text>
</View>
</View>
{/* 操作按钮 */}
<View style={profileStyles.actionContainer}>
<TouchableOpacity style={profileStyles.primaryButton}>
<Text style={profileStyles.primaryButtonText}>关注</Text>
</TouchableOpacity>
<TouchableOpacity style={profileStyles.secondaryButton}>
<Text style={profileStyles.secondaryButtonText}>消息</Text>
</TouchableOpacity>
</View>
{/* 标签页 */}
<View style={profileStyles.tabContainer}>
<TouchableOpacity
style={[
profileStyles.tab,
activeTab === 'about' && profileStyles.activeTab
]}
onPress={() => setActiveTab('about')}
>
<Text style={[
profileStyles.tabText,
activeTab === 'about' && profileStyles.activeTabText
]}>
关于
</Text>
</TouchableOpacity>
<TouchableOpacity
style={[
profileStyles.tab,
activeTab === 'skills' && profileStyles.activeTab
]}
onPress={() => setActiveTab('skills')}
>
<Text style={[
profileStyles.tabText,
activeTab === 'skills' && profileStyles.activeTabText
]}>
技能
</Text>
</TouchableOpacity>
</View>
{/* 内容区域 */}
<View style={profileStyles.content}>
{activeTab === 'about' ? (
<View>
<Text style={profileStyles.sectionTitle}>个人简介</Text>
<Text style={profileStyles.bio}>{profileData.bio}</Text>
<Text style={profileStyles.sectionTitle}>联系方式</Text>
<Text style={profileStyles.contactInfo}>📧 {profileData.email}</Text>
<Text style={profileStyles.contactInfo}>📍 {profileData.location}</Text>
</View>
) : (
<View>
<Text style={profileStyles.sectionTitle}>技能水平</Text>
{profileData.skills.map(renderSkillBar)}
</View>
)}
</View>
</ScrollView>
);
};
const profileStyles = StyleSheet.create({
container: {
flex: 1,
backgroundColor: '#fff',
},
header: {
alignItems: 'center',
paddingVertical: 30,
backgroundColor: '#f8f9fa',
},
avatar: {
width: 120,
height: 120,
borderRadius: 60,
marginBottom: 15,
borderWidth: 4,
borderColor: '#fff',
},
name: {
fontSize: 24,
fontWeight: 'bold',
color: '#333',
marginBottom: 5,
},
title: {
fontSize: 16,
color: '#666',
marginBottom: 5,
},
location: {
fontSize: 14,
color: '#999',
},
statsContainer: {
flexDirection: 'row',
backgroundColor: '#fff',
paddingVertical: 20,
marginHorizontal: 20,
marginTop: -20,
borderRadius: 10,
elevation: 3,
shadowColor: '#000',
shadowOffset: {width: 0, height: 2},
shadowOpacity: 0.1,
shadowRadius: 4,
},
statItem: {
flex: 1,
alignItems: 'center',
},
statNumber: {
fontSize: 20,
fontWeight: 'bold',
color: '#333',
},
statLabel: {
fontSize: 12,
color: '#666',
marginTop: 2,
},
statDivider: {
width: 1,
backgroundColor: '#eee',
},
actionContainer: {
flexDirection: 'row',
paddingHorizontal: 20,
paddingVertical: 20,
gap: 10,
},
primaryButton: {
flex: 1,
backgroundColor: '#007AFF',
paddingVertical: 12,
borderRadius: 8,
alignItems: 'center',
},
primaryButtonText: {
color: '#fff',
fontSize: 16,
fontWeight: 'bold',
},
secondaryButton: {
flex: 1,
backgroundColor: '#f8f9fa',
paddingVertical: 12,
borderRadius: 8,
alignItems: 'center',
borderWidth: 1,
borderColor: '#dee2e6',
},
secondaryButtonText: {
color: '#333',
fontSize: 16,
fontWeight: '500',
},
tabContainer: {
flexDirection: 'row',
backgroundColor: '#f8f9fa',
marginHorizontal: 20,
borderRadius: 8,
padding: 4,
},
tab: {
flex: 1,
paddingVertical: 10,
alignItems: 'center',
borderRadius: 6,
},
activeTab: {
backgroundColor: '#fff',
},
tabText: {
fontSize: 14,
color: '#666',
fontWeight: '500',
},
activeTabText: {
color: '#007AFF',
fontWeight: 'bold',
},
content: {
padding: 20,
},
sectionTitle: {
fontSize: 18,
fontWeight: 'bold',
color: '#333',
marginBottom: 15,
},
bio: {
fontSize: 14,
color: '#666',
lineHeight: 22,
marginBottom: 25,
},
contactInfo: {
fontSize: 14,
color: '#666',
marginBottom: 8,
},
skillItem: {
marginBottom: 20,
},
skillHeader: {
flexDirection: 'row',
justifyContent: 'space-between',
alignItems: 'center',
marginBottom: 8,
},
skillName: {
fontSize: 14,
fontWeight: '500',
color: '#333',
},
skillLevel: {
fontSize: 12,
color: '#666',
},
skillBarContainer: {
height: 6,
backgroundColor: '#f0f0f0',
borderRadius: 3,
overflow: 'hidden',
},
skillBar: {
height: '100%',
backgroundColor: '#007AFF',
borderRadius: 3,
},
});
export default ProfileCard;
🎉 本章小结
在这一章中,我们深入学习了:
- ✅ React Native 的核心组件(View、Text、Image、Button 等)
- ✅ 交互组件的使用(TouchableOpacity、TextInput)
- ✅ 列表组件(ScrollView、FlatList)的高效使用
- ✅ Flexbox 布局系统的完整掌握
- ✅ 样式系统的高级技巧
- ✅ 响应式设计的实现方法
- ✅ 综合实践项目的开发
📝 作业
- 完成个人资料卡片项目,并添加更多功能
- 尝试创建一个简单的商品列表页面
- 实践不同的布局方式,理解 Flexbox 的各种属性
准备好学习导航了吗?让我们继续第3章:导航与路由!