在这一章中,我们将完成频道页面的标签组件,分别显示简介和节目列表。以下是实现步骤:
一、创建标签组件
-
安装
react-native-tab-view由于我们已经使用了
react-native-tab-view作为顶部标签导航器的依赖库,因此无需再次安装,可以直接使用。 -
创建
Tab组件在
Album文件夹中创建Tab.tsx文件:import React from 'react'; import { View, Text, StyleSheet } from 'react-native'; import { TabView, SceneRendererProps } from 'react-native-tab-view'; interface IRoute { key: string; title: string; } interface IState { routes: IRoute[]; index: number; } class Tab extends React.Component { state: IState = { routes: [ { key: 'introduction', title: '简介' }, { key: 'albums', title: '节目' }, ], index: 1, }; onIndexChange = (index: number) => { this.setState({ index }); }; renderScene = ({ route }: { route: IRoute }) => { switch (route.key) { case 'introduction': return <Introduction />; case 'albums': return <List />; } }; renderTabBar = (props: SceneRendererProps & { navigationState: IState }) => ( <TabBar {...props} scrollEnabled tabStyle={styles.tabStyle} labelStyle={styles.label} style={styles.tabbar} indicatorStyle={styles.indicator} /> ); render() { return ( <TabView navigationState={this.state} renderScene={this.renderScene} renderTabBar={this.renderTabBar} onIndexChange={this.onIndexChange} /> ); } } const styles = StyleSheet.create({ tabStyle: { width: 80, }, label: { color: '#333', }, tabbar: { backgroundColor: '#fff', ...Platform.select({ android: { elevation: 0, borderBottomWidth: StyleSheet.hairlineWidth, borderBottomColor: '#e3e3e3', }, }), }, indicator: { backgroundColor: '#eb6d48', borderColor: '#fff', borderLeftWidth: 15, borderRightWidth: 15, }, }); export default Tab;
二、创建简介组件
-
创建
Introduction组件在
Album文件夹中创建Introduction.tsx文件:import React from 'react'; import { View, Text, StyleSheet, ScrollView } from 'react-native'; import { connect, ConnectedProps } from 'react-redux'; import { RootState } from '@/models/index'; const mapStateToProps = ({ album }: RootState) => ({ introduction: album.introduction, }); const connector = connect(mapStateToProps); type ModelState = ConnectedProps<typeof connector>; class Introduction extends React.Component<ModelState> { render() { const { introduction } = this.props; return ( <ScrollView style={styles.container}> <Text>{introduction}</Text> </ScrollView> ); } } const styles = StyleSheet.create({ container: { padding: 10, }, }); export default connector(Introduction);
三、创建节目列表组件
-
创建
List组件在
Album文件夹中创建List文件夹,并在其中创建index.tsx文件:import React from 'react'; import { FlatList, StyleSheet } from 'react-native'; import { connect, ConnectedProps } from 'react-redux'; import Item from './Item'; import { IAlbum } from '@/models/album'; import { RootState } from '@/models/index'; const mapStateToProps = ({ album }: RootState) => ({ list: album.list, }); const connector = connect(mapStateToProps); type ModelState = ConnectedProps<typeof connector>; interface IProps extends ModelState { onItemPress: (item: IAlbum, index: number) => void; } class List extends React.Component<IProps> { renderItem = ({ item, index }: ListRenderItemInfo<IAlbum>) => { return <Item data={item} index={index} onPress={this.onPress} />; }; onPress = (item: IAlbum, index: number) => { const { onItemPress } = this.props; onItemPress(item, index); }; keyExtractor = (item: IAlbum) => item.id; render() { const { list } = this.props; return ( <FlatList style={styles.container} data={list} renderItem={this.renderItem} keyExtractor={this.keyExtractor} /> ); } } const styles = StyleSheet.create({ container: { flex: 1, }, }); export default connector(List); -
创建
Item组件在
Album/List文件夹中创建Item.tsx文件:import React from 'react'; import { View, Text, StyleSheet, TouchableOpacity } from 'react-native'; import Icon from '@/assets/iconfont/index'; import { IAlbum } from '@/models/album'; export interface IProps { data: IAlbum; index: number; onPress: (item: IAlbum, index: number) => void; } class Item extends React.Component<IProps> { onPress = () => { const { onPress, data, index } = this.props; onPress(data, index); }; render() { const { data, index } = this.props; return ( <TouchableOpacity style={styles.item} onPress={this.onPress}> <Text style={styles.serial}>{index + 1}</Text> <View style={styles.centerView}> <Text style={styles.title}>{data.title}</Text> <View style={styles.info}> <View style={styles.iconView}> <Icon name="icon-V" color="#939393" /> <Text style={styles.iconText}>{data.playVolume}</Text> </View> <View style={styles.iconView}> <Icon name="icon-shengyin" color="#939393" /> <Text style={styles.iconText}>{data.duration}</Text> </View> </View> </View> <Text style={styles.date}>{data.date}</Text> </TouchableOpacity> ); } } const styles = StyleSheet.create({ item: { flexDirection: 'row', padding: 20, borderBottomWidth: StyleSheet.hairlineWidth, borderBottomColor: '#dedede', justifyContent: 'center', alignItems: 'center', }, serial: { color: '#838383', fontWeight: '800', }, title: { fontWeight: '500', color: '#333', marginBottom: 15, }, centerView: { flex: 1, marginHorizontal: 25, }, info: { flexDirection: 'row', }, iconView: { flexDirection: 'row', marginRight: 10, }, iconText: { marginHorizontal: 5, color: '#939393', fontWeight: '100', }, date: { color: '#939393', fontWeight: '100', }, }); export default Item;
四、更新频道页面
-
更新
Album页面在
Album/index.tsx中导入Tab组件,并在render方法中使用:import React from 'react'; import { View, StyleSheet } from 'react-native'; import Tab from './Tab'; class Album extends React.Component { render() { return ( <View style={styles.container}> {this.renderHeader()} <Tab /> </View> ); } } const styles = StyleSheet.create({ container: { flex: 1, }, }); export default Album;
五、总结
在本节中,我们完成了频道页面的标签组件,分别显示简介和节目列表。通过使用 react-native-tab-view 库,我们实现了标签组件的布局和功能。下一节,我们将学习如何使用手势响应系统实现频道页面的交互效果。