React Native 开发豆瓣评分(七)首页组件开发

首页内容拆分

看效果图,首页由热门影院、豆瓣热门、热门影视等列表组成,每个列表又由头加横向滑动的 电影海报列表构成。

所以可以先把页面的电影海报、评分、列表头做成组件,然后在使用 ScrollView 将内容包裹即可构成首页。

<div align=center> <img src="https://img2018.cnblogs.com/blog/1312841/201907/1312841-20190705163146521-1101885873.png" /> </div>

开发头部组件

头部组件结构简单,唯一需要注意的就是点击查看更多的时候需要跳转页面,所有需要一个自定义事件,供页面使用。

在 src 目录创建 itemsHeader.js,内容如下:

1import { Text, View, StyleSheet, TouchableWithoutFeedback } from 'react-native'; 2import PropTypes from 'prop-types'; 3import { px } from '../utils/device'; 4import Icon from 'react-native-vector-icons/AntDesign'; 5 6export default class ItemsHeader extends Component { 7 constructor(props) { 8 super(props); 9 } 10 static propTypes = { 11 title: PropTypes.string, 12 onPress: PropTypes.func 13 } 14 static defaultProps = {} 15 render() { 16 const { title, onPress } = this.props; 17 return ( 18 <View style={styles.header}> 19 <Text style={styles.title}>{title}</Text> 20 <TouchableWithoutFeedback onPress={() => onPress && onPress()}> 21 <View style={styles.getMore}> 22 <Text style={styles.moreText}>查看更多</Text> 23 <Icon name='right' size={px(30)} color='#00b600'></Icon> 24 </View> 25 </TouchableWithoutFeedback> 26 </View> 27 ) 28 } 29} 30 31const styles = StyleSheet.create({ 32 header: { 33 height: px(90), 34 width: px(750), 35 paddingLeft: px(30), 36 paddingRight: px(30), 37 backgroundColor: '#ffffff', 38 flexDirection: 'row', 39 alignItems: 'center', 40 justifyContent: 'space-between' 41 }, 42 title: { 43 fontSize: px(32), 44 color: '#333', 45 fontWeight: '600' 46 }, 47 getMore: { 48 flexDirection: 'row', 49 alignItems: 'center', 50 }, 51 moreText: { 52 fontSize: px(28), 53 marginLeft: px(30), 54 color: '#00b600', 55 marginRight: px(6) 56 } 57});

开发评分组件

评分组件需要考虑到星星大小、间距、颜色、数量,点击星星时改变星星的选中状态,并返回自定义事件 onPress 供调用者使用。

如果使用组件时调用了onPress,那么组件的值为可以改变,如果没有,那么组件应该为只读状态。

1import React, { Component } from 'react'; 2import { Text, View, StyleSheet } from 'react-native'; 3import PropTypes from 'prop-types'; 4import { px } from '../utils/device'; 5import Icon from 'react-native-vector-icons/AntDesign'; 6 7export default class Rate extends Component { 8 constructor(props) { 9 super(props); 10 this.state = { 11 value: this.props.value 12 } 13 } 14 componentWillReceiveProps(newProps) { 15 const { value } = newProps; 16 if (value !== this.state.value) { 17 this.setState({ 18 value 19 }); 20 } 21 } 22 static propTypes = {//如果使用组件时调用了onPress,那么组件默认为可以改变,如果没有,那么组件应该为只读 23 value: PropTypes.number, 24 size: PropTypes.number, 25 margin: PropTypes.number, 26 max: PropTypes.number, 27 color: PropTypes.string, 28 onPress: PropTypes.func 29 } 30 static defaultProps = { 31 value: 0, 32 size: 20, 33 margin: 5, 34 max: 5, 35 color: '#00b600' 36 } 37 bindClick = (index) => { 38 const { onPress } = this.props; 39 if (!onPress) { 40 return; 41 } 42 onPress(index + 1); 43 this.setState({ 44 value: index + 1 45 }) 46 } 47 render() { 48 const { size, margin, max, color, onPress } = this.props; 49 const { value } = this.state; 50 const defaultStars = [], activeStars = []; 51 for (let i = 0; i < max; i++) { 52 defaultStars.push(<Icon name='star' key={i} size={size} color='#ececec' onPress={() => this.bindClick(i)} style={{ marginRight: margin }}></Icon>) 53 } 54 for (let i = 0; i < value; i++) { 55 activeStars.push(<Icon name='star' key={i} size={size} color={color} onPress={() => this.bindClick(i)} style={{ marginRight: margin }}></Icon>) 56 } 57 // 选中状态的星星的宽度 58 const activeStarsWidth = (size + margin) * Math.floor(value) + size * (value - Math.floor(value)); 59 return ( 60 <View style={styles.rate}> 61 <View style={[styles.stars, styles.active, { width: activeStarsWidth }]}> 62 {activeStars.map(item => item)} 63 </View> 64 <View style={styles.stars}> 65 {defaultStars.map(item => item)} 66 </View> 67 </View> 68 ) 69 } 70} 71 72 73const styles = StyleSheet.create({ 74 rates: { 75 flexDirection: 'row', 76 position: 'relative' 77 }, 78 stars: { 79 flexDirection: 'row', 80 alignItems: 'center', 81 overflow: 'hidden', 82 flexGrow: 0 83 }, 84 active: { 85 position: 'absolute', 86 zIndex: 200, 87 left: 0, 88 top: 0 89 } 90});

开发电影海报组件

海报组件开发需要注意的是:

  1. 点击电影海报,跳转详情页面,跳转逻辑都是一样的,所以可以不用自定义事件的方式跳转,直接在组件里面调用 this.props.navigation.push 进行跳转。页面在 router 里注册后可以直接使用 this.props.navigation.push,但是组件不行。在组件中,想要使用 navigation 进行跳转,要么是使用自定义属性,将 navigation 传入组件,要么使用 react-navigation 提供的 withNavigation翻翻,withNavigation(component) 返回一个 render 函数,默认将 navigation 作出自定义属性传入组件。

  2. 有些海报图片背景纯白,和页面背景融合了,看不到边界,所以需要给他设置 border,由于 Image 组件不能设置 border,所以这里需要使用 ImageBackground 组件。

  3. title 只能为一行,产出部分省略,需要加一个 numberOfLines={1} 的属性。

    import React, { Component } from 'react'; import { Text, View, StyleSheet, ImageBackground, TouchableWithoutFeedback } from 'react-native'; import PropTypes from 'prop-types'; import { withNavigation } from 'react-navigation'; import { px } from '../utils/device'; import Rate from './rate';

    class MoviesItem extends Component { constructor(props) { super(props); } static propTypes = { data: PropTypes.object } render() { const { data, navigation } = this.props; const { id, title, cover, rating, null_rating_reason } = data; return ( <TouchableWithoutFeedback onPress={() => navigation.push('Detail', { id })}> <View style={styles.page}> <ImageBackground source={{ uri: cover.url }} style={styles.img}></ImageBackground> <Text style={styles.title} numberOfLines={1}>{title}</Text> {rating ? ( <View style={styles.rate}> <Rate value={rating.value / 2} size={px(20)} margin={px(4)} /> <Text style={styles.rateText}>{rating.value.toFixed(1)}</Text> </View> ) : ( <Text style={styles.rate}>{null_rating_reason}</Text> )} </View> </TouchableWithoutFeedback> ) } }

    export default withNavigation(MoviesItem);

    const styles = StyleSheet.create({ page: { width: px(160) }, img: { width: px(160), height: px(224), overflow: 'hidden', borderRadius: px(8), borderWidth: 1, borderStyle: 'solid', borderColor: '#f8f8f8' }, title: { fontSize: px(28), fontWeight: '600', color: '#333', marginTop: px(12), lineHeight: px(40) }, rate: { flexDirection: 'row', alignItems: 'center' }, rateText: { fontSize: px(24), color: '#999', marginLeft: px(6) } });

使用

<div align=center> <img src="https://img2018.cnblogs.com/blog/1312841/201907/1312841-20190705180554433-107267535.png"/> <img src="https://img2018.cnblogs.com/blog/1312841/201907/1312841-20190705180613907-2139270489.png"> </div>
点赞
收藏

评论区

加载中...

相关推荐

MySQL:[Err] 1292 - Incorrect datetime value: ‘0000-00-00 00:00:00‘ for column ‘CREATE_TIME‘ at row 1

文章目录问题用navicat导入数据时,报错:原因这是因为当前的MySQL不支持datetime为0的情况。解决修改sql\mode:sql\mode:SQLMode定义了MySQL应支持的SQL语法、数据校验等,这样可以更容易地在不同的环境中使用MySQL。全局s

Oracle 分组与拼接字符串同时使用

SELECTT.,ROWNUMIDFROM(SELECTT.EMPLID,T.NAME,T.BU,T.REALDEPART,T.FORMATDATE,SUM(T.S0)S0,MAX(UPDATETIME)CREATETIME,LISTAGG(TOCHAR(

手写Java HashMap源码

HashMap的使用教程HashMap的使用教程HashMap的使用教程HashMap的使用教程HashMap的使用教程22

java将前端的json数组字符串转换为列表

记录下在前端通过ajax提交了一个json数组的字符串,在后端如何转换为列表。前端数据转化与请求varcontracts{id:'1',name:'yanggb合同1'},{id:'2',name:'yanggb合同2'},{id:'3',name:'yang

2020年前端实用代码段,为你的工作保驾护航

有空的时候,自己总结了几个代码段,在开发中也经常使用,谢谢。1、使用解构获取json数据let jsonData  id: 1,status: "OK",data: 'a', 'b';let  id, status, data: number   jsonData;console.log(id, status, number )

4cast

4castpackageloadcsv.KumarAwanish发布:2020122117:43:04.501348作者:KumarAwanish作者邮箱:awanish00@gmail.com首页: