搭建开发环境
遇到问题
repositories {
maven { url 'https://maven.aliyun.com/repository/google' }
maven { url 'https://maven.aliyun.com/repository/public' }
maven { url 'https://maven.aliyun.com/repository/gradle-plugin' }
}
source 'https://mirrors.tuna.tsinghua.edu.cn/git/CocoaPods/Specs.git'
Could not find 'cocoapods' (>= 0) among N total gem(s) (Gem::LoadError)
错误
sudo gem uninstall --all
sudo gem install -n /usr/local/bin cocoapods
'value' is unavailable: introduced in iOS 12.0
In iOS Folder go to Pods/Pods.xcodeproj/xcuserdata/project.pbxproj
Change all the 'IPHONEOS_DEPLOYMENT_TARGET = 11.0' to 'IPHONEOS_DEPLOYMENT_TARGET = 12.4'. save and run.
创建项目
npx react-native init AwesomeProject --version 0.63.4
npx react-native init AwesomeTSProject --template react-native-template-typescript
npx react-native doctor
React 基础
class 组件与函数组件
import React from 'react'
import { View, Text } from 'react-native'
class ClassView extends React.Component {
constructor(props) {
super(props)
this.state = {
address: '江苏省南京市',
}
}
componentDidMount() {
setTimeout(() => {
this.setState({
address: '浙江省杭州市',
})
}, 2000)
}
render() {
const { name, age, level, sex } = this.props
const { address } = this.state
return (
<View style={{ width: '100%', height: 200, backgroundColor: '#00bcd4' }}>
<Text style={{ fontSize: 20, color: 'white' }}>
{`name=${name}, age=${age}, level=${level}, sex=${sex}`}
</Text>
<Text style={{ fontSize: 20, color: 'black' }}>{address}</Text>
</View>
)
}
}
export default ClassView
import React, { useState, useEffect, useRef } from 'react'
import {
View,
Text,
ScrollView,
useWindowDimensions,
useColorScheme,
} from 'react-native'
import InfoCard from './InfoCard'
export default () => {
const [levelUp, setLevelUp] = useState(false)
const { width, height } = useWindowDimensions()
const colorScheme = useColorScheme()
const scrollViewRef = useRef(null)
useEffect(() => {
setTimeout(() => {
setLevelUp(true)
scrollViewRef.current.scrollToEnd({ animated: true })
}, 2000)
}, [])
const getLevelView = () =>
levelUp && (
<Text style={{ fontSize: 24, color: 'green', marginVertical: 10 }}>
{`等级:高级`}
</Text>
)
const getListView = () => {
const viewList = []
for (let i = 0; i < 5; i++) {
viewList.push(
<Text style={{ fontSize: 20 }}>{`List item ${i + 1}`}</Text>
)
}
return viewList
}
const array = ['AAA', 'BBB', 'CCC', 'DDD']
return (
<View style={{ width: '100%', height: '100%', backgroundColor: '#F5F5F5' }}>
<InfoCard name='张三' age={24} sex='男' levelView={getLevelView()}>
<Text style={{ fontSize: 20, color: 'red', marginVertical: 10 }}>
{`爱好:唱、跳、RAP、篮球`}
</Text>
</InfoCard>
<ScrollView ref={scrollViewRef}>{getListView()}</ScrollView>
</View>
)
}
import React from 'react'
import { View, Text, StyleSheet } from 'react-native'
export default (props) => {
const { name, age, sex, levelView } = props
return (
<View style={styles.root}>
<Text style={[styles.txt, styles.txtBold]}>{`姓名:${name}`}</Text>
<Text style={styles.txt}>{`年龄:${age}`}</Text>
<Text style={[styles.txt, styles.txtBlue]}>{`性别:${sex}`}</Text>
{levelView}
{props.children}
</View>
)
}
const styles = StyleSheet.create({
root: {
width: '100%',
flexDirection: 'column',
},
txt: {
fontSize: 20,
color: 'black',
marginVertical: 10,
},
txtBold: {
fontWeight: 'bold',
},
txtBlue: {
color: 'blue',
},
})
RN 计数器练习
import React, { useState, useEffect } from 'react'
import { View, StyleSheet, Text } from 'react-native'
function TimerView() {
const [count, setCount] = useState(0)
useEffect(() => {
const interval = setInterval(() => {
setCount((data) => {
return data + 1
})
}, 1000)
return () => {
clearInterval(interval)
}
}, [])
return (
<View style={styles.root}>
<Text style={styles.titleTxt}>RN计数器</Text>
<Text style={styles.countTxt}>{count}</Text>
</View>
)
}
export default TimerView
const styles = StyleSheet.create({
root: {
width: '100%',
height: '100%',
backgroundColor: '#353535',
flexDirection: 'column',
alignItems: 'center',
},
titleTxt: {
marginTop: 96,
fontSize: 36,
fontWeight: 'bold',
color: 'white',
},
countTxt: {
marginTop: 64,
fontSize: 96,
fontWeight: 'bold',
color: '#1876ff',
},
})
RN 内置组件
View 组件
import React, { useEffect, useRef, useState } from 'react'
import { View, StyleSheet } from 'react-native'
export default () => {
const viewRef = useRef(null)
const [height, setHeight] = useState(100)
useEffect(() => {
setTimeout(() => {
setHeight(200)
viewRef.current.setNativeProps({
style: {
backgroundColor: 'red',
},
})
}, 2000)
}, [])
return (
<View style={styles.root}>
<View
ref={viewRef}
style={[styles.subView, { height }]}
onLayout={(event) => {
console.log(event.nativeEvent)
}}
/>
</View>
)
}
const styles = StyleSheet.create({
root: {
flexDirection: 'column',
width: '100%',
height: '100%',
backgroundColor: '#C0C0C0',
},
subView: {
width: 200,
backgroundColor: 'red',
},
})
Text 组件
import React from 'react'
import { StyleSheet, View, Text } from 'react-native'
export default () => {
return (
<View style={styles.root}>
<Text style={styles.txt}>本次期末考试</Text>
</View>
)
}
const styles = StyleSheet.create({
root: {
width: '100%',
height: '100%',
backgroundColor: '#F0F0F0',
},
txt: {
fontSize: 40,
color: '#3025ff',
textShadowColor: '#A0A0A0',
textShadowOffset: { width: 2, height: 4 },
textShadowRadius: 6,
},
})
Image 组件
import React, { useEffect, useRef } from 'react'
import { StyleSheet, View, Image } from 'react-native'
import avatar from '../assets/images/avatar.png'
import { imageUri } from '../constants/Uri'
import icon_setting from '../assets/images/icon_setting.png'
export default () => {
const imgRef = useRef(null)
useEffect(() => {
Image.getSize(
'xxx.xx.jpg',
(width, height) => {
console.log(`width=${width}, height=${height}`)
},
(error) => {
console.log(error)
}
)
Image.prefetch(imageUri)
.then((data) => {
console.log(data)
})
.catch((e) => {
console.log(e)
})
}, [])
return (
<View style={styles.root}>
<Image
ref={imgRef}
style={styles.img}
source={icon_setting}
defaultSource={avatar}
/>
</View>
)
}
const styles = StyleSheet.create({
root: {
width: '100%',
height: '100%',
backgroundColor: '#F5F5F5',
},
img: {
width: 240,
height: 240,
tintColor: 'blue',
},
})
ImageBackground 组件
import React, { useEffect, useRef, useState } from 'react'
import { StyleSheet, View, Image, Text, ImageBackground } from 'react-native'
import bg_card from '../assets/images/bg_card.png'
import icon_bank from '../assets/images/icon_bank.png'
export default () => {
return (
<View style={styles.root}>
<ImageBackground
style={styles.viewStyle}
imageStyle={styles.imgStyle}
source={bg_card}
>
<Image style={styles.icon_logo} source={icon_bank} />
<Text style={styles.txtBank}>
{`招商银行\n`}
<Text style={styles.cardTypeTxt}>{`储蓄卡\n\n`}</Text>
<Text style={styles.cardNoTxt}>●●●● ●●●● ●●●● 3068</Text>
</Text>
</ImageBackground>
</View>
)
}
const styles = StyleSheet.create({
root: {
width: '100%',
height: '100%',
flexDirection: 'column',
},
viewStyle: {
width: '100%',
height: 150,
flexDirection: 'row',
alignItems: 'flex-start',
},
imgStyle: {
resizeMode: 'cover',
borderRadius: 12,
},
icon_logo: {
width: 48,
height: 48,
borderRadius: 24,
marginLeft: 20,
marginTop: 20,
},
txtBank: {
fontSize: 24,
color: 'white',
marginLeft: 10,
marginTop: 21,
fontWeight: 'bold',
},
cardTypeTxt: {
fontSize: 20,
color: '#FFFFFFA0',
fontWeight: 'normal',
},
cardNoTxt: {
fontSize: 26,
color: 'white',
},
})
TextInput 组件
import React, { useRef, useEffect } from 'react'
import { SafeAreaView, StyleSheet, View, TextInput } from 'react-native'
export default () => {
const inputRef = useRef(null)
useEffect(() => {
setTimeout(() => {
}, 2000)
}, [])
return (
<View style={styles.root}>
<TextInput
ref={inputRef}
style={styles.input}
blurOnSubmit={true}
caretHidden={false}
editable={true}
keyboardType='number-pad'
returnKeyType='search'
onFocus={() => {}}
onBlur={() => {}}
onChange={(event) => {
console.log(event.nativeEvent)
}}
onChangeText={(text) => {
console.log(text)
}}
selectionColor='red'
selectTextOnFocus={true}
secureTextEntry={true}
/>
</View>
)
}
const styles = StyleSheet.create({
root: {
width: '100%',
height: '100%',
backgroundColor: '#F0F0F0',
},
input: {
width: '100%',
height: 56,
backgroundColor: '#D0D0D0',
fontSize: 24,
color: '#333333',
fontWeight: 'bold',
},
})
TouchableOpacity 组件
import React from 'react'
import { StyleSheet, View, Text, TouchableOpacity } from 'react-native'
export default () => {
return (
<View style={styles.root}>
<TouchableOpacity
style={styles.button}
activeOpacity={0.5}
onPress={() => {
console.log('onPress ...')
}}
onLongPress={() => {
console.log('onLongPress ...')
}}
delayLongPress={1000}
onPressIn={() => {
console.log('onPressIn ...')
}}
onPressOut={() => {
console.log('onPressOut ...')
}}
>
<Text style={styles.txt}>按钮</Text>
</TouchableOpacity>
</View>
)
}
const styles = StyleSheet.create({
root: {
width: '100%',
height: '100%',
backgroundColor: '#F0F0F0',
},
button: {
width: 300,
height: 65,
backgroundColor: '#2030FF',
justifyContent: 'center',
alignItems: 'center',
},
txt: {
fontSize: 20,
color: 'white',
fontWeight: 'bold',
},
})
TouchableHighlight 组件
import React from 'react'
import {
StyleSheet,
View,
Text,
TouchableHighlight,
TouchableWithoutFeedback,
} from 'react-native'
export default () => {
return (
<View style={styles.root}>
<TouchableHighlight
style={styles.button}
activeOpacity={0.8}
onPress={() => {
console.log('onPress ...')
}}
underlayColor='#00bcd4'
>
<Text style={styles.txt}>按钮</Text>
</TouchableHighlight>
<TouchableWithoutFeedback>
<View style={styles.button2}>
<Text style={styles.txt}>按钮</Text>
</View>
</TouchableWithoutFeedback>
</View>
)
}
const styles = StyleSheet.create({
root: {
width: '100%',
height: '100%',
backgroundColor: '#F0F0F0',
},
button: {
width: 300,
height: 65,
backgroundColor: '#2030FF',
justifyContent: 'center',
alignItems: 'center',
},
button2: {
width: 300,
height: 65,
backgroundColor: 'red',
justifyContent: 'center',
alignItems: 'center',
},
txt: {
fontSize: 20,
color: 'white',
fontWeight: 'bold',
},
})
import React from 'react'
import { StyleSheet, View, Button } from 'react-native'
export default () => {
const onPress = () => {}
return (
<View style={styles.root}>
<Button title='按 钮' color={'green'} onPress={onPress} />
</View>
)
}
const styles = StyleSheet.create({
root: {
width: '100%',
height: '100%',
justifyContent: 'center',
alignItems: 'center',
backgroundColor: '#F0F0F0',
},
})
Pressable 组件
import React from 'react'
import { StyleSheet, View, Text, Pressable } from 'react-native'
export default () => {
return (
<View style={styles.root}>
<Pressable
style={(state) => {
return [styles.button, state.pressed && styles.buttonPressed]
}}
>
{(state) => (
<Text style={state.pressed ? styles.txtPressed : styles.txt}>
按 钮
</Text>
)}
</Pressable>
</View>
)
}
const styles = StyleSheet.create({
root: {
width: '100%',
height: '100%',
backgroundColor: '#A0A0A0',
padding: 32,
},
button: {
width: 300,
height: 65,
backgroundColor: '#2030FF',
borderRadius: 10,
justifyContent: 'center',
alignItems: 'center',
},
buttonPressed: {
backgroundColor: 'white',
},
txt: {
fontSize: 20,
color: 'white',
fontWeight: 'bold',
},
txtPressed: {
fontSize: 20,
color: '#2030FF',
fontWeight: 'bold',
},
})
import React, { useRef } from 'react'
import {
StyleSheet,
ScrollView,
View,
Text,
TextInput,
Button,
Dimensions,
} from 'react-native'
const { width } = Dimensions.get('window')
export default () => {
const scrollViewRef = useRef(null)
const buildListView = () => {
const array = []
for (let i = 0; i < 20; i++) {
array.push(
<Text key={`item-${i}`} style={styles.txt}>{`List item ${i + 1}`}</Text>
)
}
return array
}
return (
<ScrollView
ref={scrollViewRef}
style={styles.root}
contentContainerStyle={styles.containerStyle}
keyboardDismissMode='on-drag'
keyboardShouldPersistTaps='handled'
onMomentumScrollBegin={() => {
}}
onMomentumScrollEnd={() => {
}}
onScroll={(event) => {
console.log(event.nativeEvent.contentOffset.y)
}}
scrollEventThrottle={16}
overScrollMode='never'
scrollEnabled={true}
contentOffset={{ y: 100 }}
showsVerticalScrollIndicator={false}
stickyHeaderIndices={[1]}
>
<TextInput style={styles.input} />
<Button
title='按钮'
onPress={() => {
scrollViewRef.current.scrollToEnd({ animated: true })
}}
/>
{buildListView()}
</ScrollView>
)
}
const styles = StyleSheet.create({
root: {
width: '100%',
height: '100%',
backgroundColor: 'white',
},
txt: {
width: '100%',
height: 56,
textAlignVertical: 'center',
fontSize: 24,
color: 'black',
},
containerStyle: {
paddingHorizontal: 16,
backgroundColor: '#E0E0E0',
paddingTop: 20,
},
input: {
width: '100%',
height: 60,
backgroundColor: '#ff000050',
},
})
FlatList 组件
import React, { useRef, useEffect } from 'react'
import { StyleSheet, View, FlatList, Text } from 'react-native'
const data = [
1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20,
]
export default () => {
const flatListRef = useRef(null)
useEffect(() => {
setTimeout(() => {
flatListRef.current.scrollToEnd({
animated: true,
})
}, 2000)
}, [])
const renderItem = ({ item, index }) => {
return <Text style={styles.txt}>{`List item ${item}`}</Text>
}
const renderItem2 = ({ item, index }) => {
return <Text style={styles.txt2}>{`List item ${item}`}</Text>
}
const ListHeader = (
<View style={styles.header}>
<Text style={styles.extraTxt}>列表头部</Text>
</View>
)
const ListFooter = (
<View style={[styles.header, styles.footer]}>
<Text style={styles.extraTxt}>列表尾部</Text>
</View>
)
const ListEmpty = (
<View style={styles.listEmpty}>
<Text style={styles.extraTxt}>暂时无数据哦~</Text>
</View>
)
return (
<FlatList
ref={flatListRef}
style={styles.flatlist}
data={data}
renderItem={renderItem}
keyExtractor={(_, index) => `item-${index}`}
contentContainerStyle={styles.containerStyle}
showsVerticalScrollIndicator={false}
onScroll={(event) => {
console.log(event.nativeEvent.contentOffset.y)
}}
keyboardDismissMode='on-drag'
keyboardShouldPersistTaps='handled'
ListHeaderComponent={ListHeader}
ListFooterComponent={ListFooter}
ListEmptyComponent={ListEmpty}
ItemSeparatorComponent={<View style={styles.separator} />}
initialNumToRender={15}
inverted={false}
/>
)
}
const styles = StyleSheet.create({
flatlist: {
width: '100%',
height: '100%',
},
txt: {
width: '100%',
height: 56,
fontSize: 24,
color: 'black',
textAlignVertical: 'center',
},
txt2: {
width: 200,
height: 200,
fontSize: 24,
color: 'black',
textAlign: 'center',
textAlignVertical: 'center',
},
containerStyle: {
paddingHorizontal: 16,
paddingTop: 20,
backgroundColor: '#F5F5F5',
},
header: {
width: '100%',
height: 48,
backgroundColor: '#00ff0030',
justifyContent: 'center',
alignItems: 'center',
},
footer: {
backgroundColor: '#ff000030',
},
listEmpty: {
width: '100%',
height: 400,
justifyContent: 'center',
alignItems: 'center',
},
extraTxt: {
fontSize: 20,
color: '#666666',
textAlignVertical: 'center',
},
separator: {
width: '100%',
height: 2,
backgroundColor: '#D0D0D0',
},
})
SectionList, StatusBar 组件
import React, { useRef, useEffect, useSatte, useState } from 'react'
import {
StyleSheet,
View,
Text,
SectionList,
RefreshControl,
StatusBar,
} from 'react-native'
import { SectionData } from '../constants/Data'
export default () => {
const sectionListRef = useRef(null)
const [refreshing, setRefreshing] = useState(false)
useEffect(() => {
setTimeout(() => {
}, 2000)
}, [])
const renderItem = ({ item, index, section }) => {
return <Text style={styles.txt}>{item}</Text>
}
const ListHeader = (
<View style={styles.header}>
<Text style={styles.extraTxt}>列表头部</Text>
</View>
)
const ListFooter = (
<View style={[styles.header, styles.footer]}>
<Text style={styles.extraTxt}>列表尾部</Text>
</View>
)
const renderSectionHeader = ({ section }) => {
return <Text style={styles.sectionHeaderTxt}>{section.type}</Text>
}
return (
<View style={styles.root}>
<StatusBar
barStyle='light-content'
backgroundColor='transparent'
animated={true}
translucent={true}
hidden={false}
/>
<SectionList
ref={sectionListRef}
style={styles.sectionList}
sections={SectionData}
renderItem={renderItem}
keyExtractor={(item, index) => `${item}-${index}`}
contentContainerStyle={styles.containerStyle}
showsVerticalScrollIndicator={false}
onScroll={(event) => {
}}
keyboardDismissMode='on-drag'
keyboardShouldPersistTaps='handled'
ListHeaderComponent={ListHeader}
ListFooterComponent={ListFooter}
renderSectionHeader={renderSectionHeader}
ItemSeparatorComponent={() => <View style={styles.separator} />}
stickySectionHeadersEnabled={true}
refreshControl={
<RefreshControl
refreshing={refreshing}
onRefresh={() => {
console.log('onRefresh ...')
setRefreshing(true)
setTimeout(() => {
setRefreshing(false)
}, 1000)
}}
/>
}
onEndReached={() => {
console.log('onEndReached ...')
}}
onEndReachedThreshold={0.2}
/>
</View>
)
}
const styles = StyleSheet.create({
root: {
width: '100%',
height: '100%',
},
sectionList: {
width: '100%',
height: '100%',
},
txt: {
width: '100%',
height: 56,
fontSize: 20,
color: '#333333',
textAlignVertical: 'center',
paddingLeft: 16,
},
containerStyle: {
backgroundColor: '#F5F5F5',
},
header: {
width: '100%',
height: 48,
backgroundColor: '#0000ff80',
justifyContent: 'center',
alignItems: 'center',
},
footer: {
backgroundColor: '#ff000030',
},
extraTxt: {
fontSize: 20,
color: '#666666',
textAlignVertical: 'center',
},
sectionHeaderTxt: {
width: '100%',
height: 36,
backgroundColor: '#DDDDDD',
textAlignVertical: 'center',
paddingLeft: 16,
fontSize: 20,
color: '#333333',
fontWeight: 'bold',
},
separator: {
width: '100%',
height: 2,
backgroundColor: '#D0D0D0',
},
})
Modal 组件
import React, { useState } from 'react'
import {
StyleSheet,
View,
Modal,
Text,
Button,
SectionList,
TouchableOpacity,
Image,
} from 'react-native'
import icon_close_modal from '../assets/images/icon_close_modal.png'
import { SectionData } from '../constants/Data'
export default () => {
const [visible, setVisible] = useState(false)
const showModal = () => {
setVisible(true)
}
const hideModal = () => {
setVisible(false)
}
const renderItem = ({ item, index, section }) => {
return <Text style={styles.txt}>{item}</Text>
}
const ListHeader = (
<View style={styles.header}>
<Text style={styles.extraTxt}>列表头部</Text>
<TouchableOpacity style={styles.closeButton} onPress={() => hideModal()}>
<Image style={styles.closeImg} source={icon_close_modal} />
</TouchableOpacity>
</View>
)
const ListFooter = (
<View style={[styles.header, styles.footer]}>
<Text style={styles.extraTxt}>列表尾部</Text>
</View>
)
const renderSectionHeader = ({ section }) => {
return <Text style={styles.sectionHeaderTxt}>{section.type}</Text>
}
return (
<View style={styles.root}>
<Button title='按钮' onPress={() => showModal()} />
<Modal
visible={visible}
onRequestClose={() => hideModal()}
transparent={true}
statusBarTranslucent={true}
animationType='slide'
onShow={() => console.log('onShow ...')}
onDismiss={() => console.log('onDismiss ...')}
>
<View style={styles.blank} />
<View style={styles.content}>
<SectionList
style={styles.sectionList}
sections={SectionData}
renderItem={renderItem}
keyExtractor={(item, index) => `${item}-${index}`}
contentContainerStyle={styles.containerStyle}
showsVerticalScrollIndicator={false}
ListHeaderComponent={ListHeader}
ListFooterComponent={ListFooter}
renderSectionHeader={renderSectionHeader}
ItemSeparatorComponent={() => <View style={styles.separator} />}
stickySectionHeadersEnabled={true}
/>
</View>
</Modal>
</View>
)
}
const styles = StyleSheet.create({
root: {
width: '100%',
height: '100%',
paddingHorizontal: 16,
},
blank: {
width: '100%',
height: '10%',
backgroundColor: '#00000050',
},
content: {
width: '100%',
height: '90%',
backgroundColor: '#ff000030',
},
sectionList: {
width: '100%',
height: '100%',
},
txt: {
width: '100%',
height: 56,
fontSize: 20,
color: '#333333',
textAlignVertical: 'center',
paddingLeft: 16,
},
containerStyle: {
backgroundColor: '#F5F5F5',
},
header: {
width: '100%',
height: 48,
backgroundColor: 'white',
justifyContent: 'center',
alignItems: 'center',
},
footer: {
backgroundColor: '#ff000030',
},
extraTxt: {
fontSize: 20,
color: '#666666',
textAlignVertical: 'center',
},
sectionHeaderTxt: {
width: '100%',
height: 36,
backgroundColor: '#DDDDDD',
textAlignVertical: 'center',
paddingLeft: 16,
fontSize: 20,
color: '#333333',
fontWeight: 'bold',
},
separator: {
width: '100%',
height: 2,
backgroundColor: '#D0D0D0',
},
closeButton: {
width: 24,
height: 24,
position: 'absolute',
right: 16,
},
closeImg: {
width: 24,
height: 24,
},
})
Switch 组件
import React, { useState } from 'react'
import { StyleSheet, View, Switch } from 'react-native'
export default () => {
const [switchValue, setSwitchValue] = useState(true)
return (
<View style={styles.root}>
<Switch
value={switchValue}
onValueChange={(value) => {
setSwitchValue(value)
}}
disabled={false}
trackColor={{ true: 'red', false: '#808080' }}
thumbColor={switchValue ? '#2030ff' : '#303030'}
/>
</View>
)
}
const styles = StyleSheet.create({
root: {
width: '100%',
height: '100%',
},
})
个人信息页面 练习
import React, { useState } from 'react'
import {
StyleSheet,
View,
ImageBackground,
Image,
Text,
TouchableOpacity,
SectionList,
Modal,
StatusBar,
} from 'react-native'
import icon_bg from '../assets/images/icon_bg.png'
import icon_menu from '../assets/images/icon_menu.png'
import icon_share from '../assets/images/icon_share.png'
import avatar from '../assets/images/default_avatar.png'
import icon_add from '../assets/images/icon_add.png'
import icon_code from '../assets/images/icon_code.png'
import icon_male from '../assets/images/icon_male.png'
import icon_setting from '../assets/images/icon_setting.png'
import icon_1 from '../assets/images/icon_1.png'
import icon_2 from '../assets/images/icon_2.png'
import icon_3 from '../assets/images/icon_3.png'
import icon_close_modal from '../assets/images/icon_close_modal.png'
import { SectionData } from '../constants/Data'
export default () => {
const [tabIndex, setTabIndex] = useState(0)
const [visible, setVisible] = useState(false)
const getContent = () => {
const contentStyles = StyleSheet.create({
icon: {
width: 96,
height: 96,
resizeMode: 'contain',
},
desc: {
fontSize: 16,
marginTop: 16,
},
button: {
width: 76,
height: 28,
borderRadius: 14,
borderWidth: 1,
borderColor: '#C0C0C0',
textAlign: 'center',
textAlignVertical: 'center',
marginTop: 12,
color: '#333333',
},
})
const array = []
array[0] = (
<>
<Image style={contentStyles.icon} source={icon_1} />
<Text style={contentStyles.desc}>用一句话,分享今天的快乐吧~</Text>
<Text style={contentStyles.button}>去分享</Text>
</>
)
array[1] = (
<>
<Image style={contentStyles.icon} source={icon_2} />
<Text style={contentStyles.desc}>快去收藏你喜欢的作品吧~</Text>
<Text style={contentStyles.button}>去收藏</Text>
</>
)
array[2] = (
<>
<Image style={contentStyles.icon} source={icon_3} />
<Text style={contentStyles.desc}>你还没有给作品点赞哦~</Text>
<Text style={contentStyles.button}>去点赞</Text>
</>
)
return array
}
const renderModal = () => {
const modalStyles = StyleSheet.create({
root: {
width: '100%',
height: '100%',
backgroundColor: 'transparent',
flexDirection: 'column',
},
content: {
width: '100%',
height: '90%',
backgroundColor: 'white',
},
nameTxt: {
width: '100%',
height: 46,
textAlignVertical: 'center',
paddingLeft: 16,
fontSize: 16,
color: '#333333',
},
typeTxt: {
width: '100%',
height: 36,
backgroundColor: '#E0E0E0',
textAlignVertical: 'center',
paddingLeft: 16,
fontSize: 16,
color: '#666666',
},
listHeader: {
width: '100%',
flexDirection: 'column',
paddingTop: 96,
},
titleLayout: {
width: '100%',
height: 46,
backgroundColor: 'white',
borderTopLeftRadius: 12,
borderTopRightRadius: 12,
justifyContent: 'center',
alignItems: 'center',
},
titleTxt: {
fontSize: 18,
color: '#333333',
fontWeight: 'bold',
},
closeButton: {
position: 'absolute',
right: 16,
},
closeImg: {
width: 24,
height: 24,
},
})
return (
<Modal
visible={visible}
onRequestClose={() => setVisible(false)}
transparent={true}
animationType='slide'
statusBarTranslucent={true}
>
<View style={modalStyles.root}>
<View style={modalStyles.listHeader}>
<View style={modalStyles.titleLayout}>
<Text style={modalStyles.titleTxt}>粉丝列表</Text>
<TouchableOpacity
style={modalStyles.closeButton}
onPress={() => setVisible(false)}
>
<Image style={modalStyles.closeImg} source={icon_close_modal} />
</TouchableOpacity>
</View>
</View>
<View style={modalStyles.content}>
<SectionList
sections={SectionData}
renderItem={({ item }) => (
<Text style={modalStyles.nameTxt}>{item}</Text>
)}
keyExtractor={(item, index) => `${item}-${index}`}
renderSectionHeader={({ section }) => (
<Text style={modalStyles.typeTxt}>{section.type}</Text>
)}
/>
</View>
</View>
</Modal>
)
}
const renderDashboard = () => {
return (
<ImageBackground
style={styles.imgBg}
source={icon_bg}
imageStyle={styles.bgImg}
>
<View style={styles.titleBar}>
<Image style={styles.iconMenu} source={icon_menu} />
<Image style={styles.iconShare} source={icon_share} />
</View>
<View style={styles.infoLayout}>
<View style={styles.avatarLayout}>
<Image style={styles.avatarImg} source={avatar} />
<Image style={styles.iconAdd} source={icon_add} />
<View style={styles.nameLayout}>
<Text style={styles.nameTxt}>大公爵</Text>
<View style={styles.idLayout}>
<Text style={styles.idTxt}>小红书号:118302851</Text>
<Image style={styles.iconCode} source={icon_code} />
</View>
</View>
</View>
</View>
<Text style={styles.descTxt}>点击关注,填写简介</Text>
<View style={styles.sexView}>
<Image style={styles.sexImg} source={icon_male} />
</View>
<View style={styles.countLayout}>
<TouchableOpacity
style={styles.itemLayout}
onPress={() => setVisible(true)}
>
<Text style={styles.itemCount}>142</Text>
<Text style={styles.itemLabel}>关注</Text>
</TouchableOpacity>
<View style={styles.itemLayout}>
<Text style={styles.itemCount}>2098</Text>
<Text style={styles.itemLabel}>粉丝</Text>
</View>
<View style={styles.itemLayout}>
<Text style={styles.itemCount}>1042</Text>
<Text style={styles.itemLabel}>获赞与收藏</Text>
</View>
<View style={{ flex: 1 }} />
<TouchableOpacity style={styles.editButton} activeOpacity={0.5}>
<Text style={styles.editTxt}>编辑资料</Text>
</TouchableOpacity>
<TouchableOpacity style={styles.settingButton} activeOpacity={0.5}>
<Image style={styles.iconSetting} source={icon_setting} />
</TouchableOpacity>
</View>
</ImageBackground>
)
}
const renderTabs = () => {
return (
<>
<View style={styles.tabsLayout}>
<TouchableOpacity style={styles.tab} onPress={() => setTabIndex(0)}>
<Text
style={tabIndex === 0 ? styles.tabTxtSelected : styles.tabTxt}
>
笔记
</Text>
<View style={[styles.tabLine, tabIndex !== 0 && styles.hide]} />
</TouchableOpacity>
<TouchableOpacity style={styles.tab} onPress={() => setTabIndex(1)}>
<Text
style={tabIndex === 1 ? styles.tabTxtSelected : styles.tabTxt}
>
收藏
</Text>
<View style={[styles.tabLine, , tabIndex !== 1 && styles.hide]} />
</TouchableOpacity>
<TouchableOpacity style={styles.tab} onPress={() => setTabIndex(2)}>
<Text
style={tabIndex === 2 ? styles.tabTxtSelected : styles.tabTxt}
>
赞过
</Text>
<View style={[styles.tabLine, , tabIndex !== 2 && styles.hide]} />
</TouchableOpacity>
</View>
<View style={styles.contentLayout}>{getContent()[tabIndex]}</View>
</>
)
}
return (
<View style={styles.root}>
<StatusBar
barStyle='light-content'
translucent={true}
backgroundColor='transparent'
/>
{renderDashboard()}
{renderTabs()}
{renderModal()}
</View>
)
}
const styles = StyleSheet.create({
root: {
width: '100%',
height: '100%',
backgroundColor: '#F5F5F5',
},
imgBg: {
width: '100%',
paddingTop: 20,
},
bgImg: {
resizeMode: 'stretch',
},
titleBar: {
width: '100%',
flexDirection: 'row',
alignItems: 'center',
marginBottom: 8,
marginTop: 16,
},
iconMenu: {
width: 25,
height: 25,
resizeMode: 'contain',
marginHorizontal: 16,
},
iconShare: {
width: 25,
height: 25,
resizeMode: 'contain',
position: 'absolute',
right: 16,
},
infoLayout: {
flexDirection: 'column',
padding: 16,
},
avatarLayout: {
width: '100%',
flexDirection: 'row',
alignItems: 'flex-end',
},
avatarImg: {
width: 86,
height: 86,
borderRadius: 48,
backgroundColor: 'white',
},
iconAdd: {
width: 24,
height: 24,
marginLeft: -20,
marginBottom: 2,
},
nameLayout: {
flexDirection: 'column',
marginBottom: 16,
marginLeft: 8,
},
nameTxt: {
fontSize: 22,
color: 'white',
fontWeight: 'bold',
},
idLayout: {
flexDirection: 'row',
alignItems: 'center',
marginTop: 12,
},
idTxt: {
fontSize: 14,
color: 'white',
},
iconCode: {
width: 12,
height: 12,
marginLeft: 4,
tintColor: 'white',
},
descTxt: {
fontSize: 16,
color: 'white',
marginLeft: 16,
marginBottom: 8,
},
sexView: {
marginTop: 6,
width: 24,
height: 18,
backgroundColor: '#ffffff60',
borderRadius: 9,
justifyContent: 'center',
alignItems: 'center',
marginBottom: 16,
marginLeft: 16,
},
sexImg: {
width: 12,
height: 12,
resizeMode: 'contain',
tintColor: '#1876ff',
},
countLayout: {
width: '100%',
flexDirection: 'row',
alignItems: 'center',
paddingHorizontal: 16,
marginBottom: 28,
},
itemLayout: {
flexDirection: 'column',
alignItems: 'center',
marginRight: 16,
},
itemCount: {
fontSize: 16,
color: 'white',
},
itemLabel: {
fontSize: 14,
color: '#ffffffc0',
marginTop: 3,
},
editButton: {
width: 80,
height: 32,
borderRadius: 16,
borderColor: 'white',
borderWidth: 1,
justifyContent: 'center',
alignItems: 'center',
},
editTxt: {
fontSize: 14,
color: '#ffffffE0',
},
settingButton: {
width: 46,
height: 32,
borderRadius: 16,
marginLeft: 12,
borderColor: 'white',
borderWidth: 1,
justifyContent: 'center',
alignItems: 'center',
},
iconSetting: {
width: 20,
height: 20,
resizeMode: 'contain',
tintColor: 'white',
},
tabsLayout: {
width: '100%',
height: 46,
flexDirection: 'row',
backgroundColor: 'white',
borderTopLeftRadius: 12,
borderTopRightRadius: 12,
borderBottomWidth: 1,
borderBottomColor: '#E0E0E0',
justifyContent: 'center',
alignItems: 'center',
marginTop: -12,
paddingTop: 4,
},
tab: {
flexDirection: 'column',
width: 64,
height: '100%',
justifyContent: 'center',
alignItems: 'center',
},
tabTxt: {
fontSize: 18,
fontWeight: 'bold',
color: '#909090',
},
tabTxtSelected: {
fontSize: 18,
fontWeight: 'bold',
color: '#333333',
},
tabLine: {
width: 28,
height: 2,
backgroundColor: '#f05856',
marginTop: 4,
},
hide: {
backgroundColor: 'transparent',
},
contentLayout: {
width: '100%',
flexGrow: 1,
backgroundColor: '#FAFAFA',
flexDirection: 'column',
alignItems: 'center',
paddingTop: 64,
},
})
参考资料