【稀饭】react native 实战系列教程之首页列表UI实现

前端之家收集整理的这篇文章主要介绍了【稀饭】react native 实战系列教程之首页列表UI实现前端之家小编觉得挺不错的,现在分享给大家,也给大家做个参考。

首页设计与实现

首先,这章节讲的是首页内容的设计与实现,不包括主界面的设计,因为一开始入手,我希望能立马获取到数据并能展示出来,后面再来搭木积似的一步一步把整体框架做起来。

设计

(图丑,莫见怪~)

主界面的设计如下

首页的设计如下

有人可能会觉得,为什么不把TitleBar抽出来放在主界面,而要单独放在每个页面里。因为,这个跟你把Navigator(页面导航器)放在什么地方有关系,现在先不说为什么,就这么认为吧,不是每个页面都需要TitleBar的,放在各自页面,就可以很好的控制是否需要标题栏,需要时候再添加

实现

这章节先实现首页部分。可以看到,最新和最热的内容上结构是一致的,所以,先定义一个组件来显示即可。

先来看下项目的目录结构:

现在用的IDE是WebStorm(之前都是用sublime text 3 敲的代码,那个苦啊/(ㄒoㄒ)/~~)。

自定义组件

新建好js/component 文件夹之后,在component文件夹下创建DramaComponent.js文件

初始代码如下:

import React,{Component} from 'react';
import {
    View,Text,} from 'react-native';

class DramaComponent extends Component{
    constructor(props){
        super(props);
    }

    render(){
        return(
            <View> <Text> 我是列表内容 </Text> </View> ); } }

然后,我们这个组件是要作为公共组件的,要给别的组件引用,因此,我们需要将它‘暴露’出去,需要做如下处理:

export default class DramaComponent extends Component {
    ...
}

就是在定义class前加上export default

接着,我们在index.android.js使用import引用它:

import React,{ Component} from 'react';
import {
  AppRegistry,View,} from 'react-native';

import DramaComponent from './js/component/DramaComponent';

class XiFan extends Component {

  render(){
    return(
        <DramaComponent />
    );
  }
}

AppRegistry.registerComponent('XiFan',() => XiFan);

看下有没有正常被引用,使用命令行cd到项目根目录下,执行命令(如果已经启动并运行过了,模拟器下双击键盘R键,重新加载即可)

react-native run-android

可以看到组件可以被正常使用并显示了。(默认你已经配置好调试环境,已经连接模拟器并设置好IP)

组件UI编写

可以正常被调用之后,我们就开始编写具体的UI层。

这是一个列表,我们优先想到的是用ListView这个控件

export default class DramaComponent extends Component {
    constructor(props) {
        super(props);
        this.state = {
            movies:new ListView.DataSource({
                rowHasChanged:(r1,r2) => r1!=r2,}),}
    }
    //渲染ListView item view
    _renderMovieView(movie){

    }
    //ListView 拉到底部调用
    _onEndReached(){

    }

    render() {
        return (
            <ListView
                dataSource = {this.state.movies}
                renderRow = {this._renderMovieView.bind(this)}
                style = {styles.listview}
                initialListSize = {10}
                pageSize = {10}
                onEndReachedThreshold = {5}
                onEndReached = {this._onEndReached.bind(this)}
                enableEmptySections = {true}
                contentContainerStyle = {styles.grid}
            />
        );
    }
}

ListView的几个属性

dataSource:数据源

renderRow:ListView渲染的每一item view

initialListSize:初始渲染item的个数

pageSize:每次事件循环(每帧)渲染的行数

onEndReachedThreshold:调用onEndReached之前的临界值,单位是像素

onEndReached:当所有的数据都已经渲染过,并且列表被滚动到距离最底部不足onEndReachedThreshold个像素的距离时调用

更多属性介绍可以看下文档介绍

dataSource是一个动态数据,会变化,所以使用state来绑定数据。

每一部剧包含:影片名称标题、主要演员、图片,还有点击item跳转时的详情链接,所以数据结构设计如下:

var dramaItem ={
    name:'',//影片名称
    title:'',//标题
    actor:'',//演员
    pic:'',//图片地址
    url:'',//详情链接
};

接着,我们要将item view绘制出来,_renderMovieView函数实现如下:

//渲染ListView item view
    _renderMovieView(movie){
        return(
            <View style={styles.row} key={movie.url}> <TouchableOpacity onPress={this._onItemPress.bind(this,movie)} activeOpacity={0.8} > <View> <Image source={{uri:movie.pic}} style={styles.thumbnail}> <Text style={styles.title}>{movie.title}</Text> </Image> <Text numberOfLines={1} style={styles.name}>{movie.name}</Text> <Text numberOfLines={1} style={styles.actor}>{movie.actor}</Text> </View> </TouchableOpacity> </View> ); } //item 点击事件 _onItemPress(movie){ console.log(movie); }

这里关于UI如何布局就不详细说了,看着UI效果大家应该都知道怎么写了。这里需要注意的是TouchableOpacity 的onPress方法需要在点击的时候将movie对象传递下去,所以这里会有个组件的函数怎么传参的问题。

这里有两种方法

@H_502_327@
  • 第一种

    如上面代码所示,在函数后面调用bind,第一个参数是上下文对象,后面就是参数对象数组

  • onPress={this._onItemPress.bind(this,movie)}
    @H_502_327@
  • 第二种
  • onPress={()=>this._onItemPress(movie)}

    一般使用第一种方法,因为很多时候在定义的方法_onItemPress内,会调用this.xxxx,这时候如果你没有使用_onItemPress.bind(this),将上下文对象传递下去,那么会报错,提示找不到xxxx方法或对象。

    最后,我们在组件生命周期componentDidMount方法内,进行模拟数据:

    componentDidMount(){
            var dramaItem ={
                name:'原来是美男啊',//影片名称
                title:'第16集中字',//标题
                actor:'张根硕',//演员
                pic:'http://img.y3600.com/d/file/p/2016/08/24/b216e94526fbf2d49f40dc5aaa1897a4.jpg',//图片地址
                url:'http://www.y3600.com/hanju/2016/907.html',//详情链接
            };
            var datas = [];
            datas.push(dramaItem);
            this.setState({
                movies:this.state.movies.cloneWithRows(datas),});
        }

    这里关键是通过setState进行状态更新,进而刷新页面,要注意的是调用cloneWithRows进行数据填充,datas是个数据集合。关键代码

    this.setState({ movies:this.state.movies.cloneWithRows(datas),});

    然后重新刷新(双击RR)

    这里只模拟了一条数据(多条数据多次调用datas.push即可),可以看到已经可以正常显示了,点击item也有log输出了(通过android studio查看logcat)

    至此,我们已经实现了列表数据UI的编写,如果你运行上面的代码,你会发现少了些样式style,那下面贴下这节的全部代码

    import React,ListView,StyleSheet,TouchableOpacity,Dimensions,Image
    } from 'react-native';
    
    export default class DramaComponent extends Component {
        constructor(props) {
            super(props);
            this.state = {
                movies:new ListView.DataSource({
                    rowHasChanged:(r1,}
        }
    
        componentDidMount(){
            var dramaItem ={
                name:'原来是美男啊',});
        }
    
        //渲染ListView item view
        _renderMovieView(movie){
            return(
                <View style={styles.row} key={movie.url}> <TouchableOpacity onPress={this._onItemPress.bind(this,movie)} activeOpacity={0.8} > <View> <Image source={{uri:movie.pic}} style={styles.thumbnail}> <Text style={styles.title}>{movie.title}</Text> </Image> <Text numberOfLines={1} style={styles.name}>{movie.name}</Text> <Text numberOfLines={1} style={styles.actor}>{movie.actor}</Text> </View> </TouchableOpacity> </View> ); } _onItemPress(movie){ console.log(movie); } //ListView 拉到底部调用 _onEndReached(){ console.log('加载下一页'); } render() { return ( <ListView  dataSource = {this.state.movies} renderRow = {this._renderMovieView.bind(this)} style = {styles.listview} initialListSize = {10} pageSize = {10} onEndReachedThreshold = {5} onEndReached = {this._onEndReached.bind(this)} enableEmptySections = {true} contentContainerStyle = {styles.grid} /> ); } } const WIN_WIDTH = Dimensions.get('window').width; var width = WIN_WIDTH/3; var styles = StyleSheet.create({ grid:{ justifyContent: 'flex-start',flexDirection: 'row',flexWrap: 'wrap' },row:{ height:200,width:width,flexDirection:'column',justifyContent:'center',alignItems:'center',paddingTop:10,paddingBottom:10,marginTop:5,marginBottom:5,},thumbnail:{ flex:1,width:width-20,height:140,justifyContent:'flex-end',resizeMode: Image.resizeMode.strech,title:{ fontSize:10,textAlign:'center',color:'white',backgroundColor:'#27272790',name:{ fontSize:12,color:'black',marginTop:8,actor:{ fontSize:10,color:'#707070',listview:{ backgroundColor:'#f5fcff',});

    这里可能要提一下,我们使用的是ListView,但是最后效果好像是一个Android中GridView的效果,或者你可能会有疑问react native中如何实现GridView的效果。其实在react native中使用ListView在配合好style就可以实现GridView的效果了,主要样式如下:

    grid:{ justifyContent: 'flex-start',flexDirection: 'row',flexWrap: 'wrap' },row:{ height:200,flexDirection:'column',justifyContent:'center',alignItems:'center',paddingTop:10,paddingBottom:10,marginTop:5,marginBottom:5,},

    grid是ListView的contentContainerStyle,justifyContent: ‘flex-start’使每个item靠左,flexDirection: ‘row’让item是水平从左往右排列,flexWrap: ‘wrap’是当一行item排列不下时自动换行。row是每个item的style,需要设置好height和width。

    总结

    本节讲了应用的的整体设计,并实现了列表UI,只是数据还是模拟阶段,主要技术点在于ListView的使用,熟悉dataSource、renderRow、ListView.DataSource、cloneWithRows以及函数的传参问题。下一节,我们在实现真实数据的获取和解析,使用到cheerio这个html解析库,如果你还不知道这是用来干嘛的,你可以先去了解下

    原文链接:https://www.f2er.com/react/306131.html

    猜你在找的React相关文章