ReactNative中SectionList实现条目GridView效果

本文纯原创,纯手打,请大神多多指教。转载请注明出处!
react-native版本:0.48; 开发环境win10+VScode; 目标平台:安卓(暂时没有适配苹果); 最后更新时间:2017.09.11;

在ReactNative,想做个Android中分组GridView的效果,搜索了半天没找到解决办法,于是自己瞎摸索出来了一套效果,目前就是用SectionList嵌套FlatList,但是这肯定不是最优的方法,还请大神指点
先看下效果图


最终完成效果

  1. 数据格式
    var data0={name:'外勤签到',img:Images.oaWQQD,onPress:()=>alert('跳转页面----外勤签到') }
    var data1={name:'考勤打卡',img:Images.oaKQDK}
    var data2={name:'审批',img:Images.oaSP}
    var data3={name:'日志',img:Images.oaRZ}
    OAData.push(data0)
    OAData.push(data1)
    OAData.push(data2)
    var AllMenu2=[
    {key:0,title:'办公',data:OAData},
    {key:1,title:'营销',data:YXData},
    ]
    2.代码
    源代码地址:https://github.com/MyPublicGitHub/Test.git

     import React from 'react'
     import { StyleSheet, View, Image, Text, ImageBackground, TouchableOpacity, ToastAndroid, SectionList, FlatList ,RefreshControl} from 'react-native'
     import Images from '../images/ImageList'
     import Api from '../api/Api'
     import GV from '../utils/GlobalVariable'
     import * as Progress from 'react-native-progress';
     var AllMenu = [];
     var Dimensions = require('Dimensions');//获取屏幕的宽高 
     var ScreenWidth = Dimensions.get('window').width;
     var ScreenHeight = Dimensions.get('window').height;
     
     class WorksView extends React.Component {
         constructor(props) {
             super(props);
             this.state = {
                 isLoading: false,
             };
         }
    
     static navigationOptions = {
         headerTitle: <Text style={{ alignSelf: 'center', fontSize: 16, color: 'black', }}>工作台</Text>,
         headerLeft: null,
         headerStyle: {
             height: 40,
         }
     }
    
     componentDidMount() {
         this._getModuleDefault()
     }
     _getModuleDefault() {
         console.log("令牌" + GV.ACCESS_TOKEN)
    
         if (GV.ACCESS_TOKEN !== '') {
             var url = 'http://api.test.zhu-ku.com/zhuku/ws/system/sysroleapp/selectUserRoleAll/' + GV.ACCESS_TOKEN;
             var header = {
                 method: 'get',
             }
    
             this.setState({
                 isLoading: true
             })
    
             fetch(url, header)
                 .then((response) => {
                     return response.json()
                 })
                 .then((responseJson) => {
    
                     if (responseJson.statusCode == '0000') {
                         //ToastAndroid.show('获取权限成功', ToastAndroid.SHORT);
                         this._initItem(responseJson.returnData);
                     } else {
                         //alert(responseJson.statusDesc + 'response')
                         ToastAndroid.show('获取权限失败:' + responseJson.statusDesc, ToastAndroid.SHORT);
                     }
                     this.setState({
                         isLoading: false
                     })
    
                 })
                 .catch((error) => {
                     alert(error)
                     this.setState({
                         isLoading: false
                     })
                 })
             //ToastAndroid.show('132132', ToastAndroid.SHORT);
         }
     }
    
     _renderItem = ({ info }) => null
    
     _renderSectionHeader = ({ section }) =>
         <View>
             <Text style={styles.viewItemHeader}>{section.title}</Text>
             <FlatList
                 data={section.data}
                 style={styles.flastList}
                 numColumns={4}
                 renderItem={({ item }) =>
                     <TouchableOpacity onPress={item.onPress}>
                         <View style={styles.viewRow}>
                             <Image source={item.img} style={styles.imageItem} />
                             <Text style={styles.textItem}>{item.name}</Text>
                         </View>
                     </TouchableOpacity>
                 }
             />
         </View>
    
    
     render() {
         return (
             this.state.isLoading ?
                 <View style={styles.load}>
                     <Progress.CircleSnail style={{ margin: 10, alignSelf: 'center' }} color={['red', 'green', 'blue', 'black', 'yellow']} size={30} />
                     <Text>正在加载...</Text>
                 </View>
                 :
                 <SectionList
                     style={styles.background}
                     renderSectionHeader={this._renderSectionHeader}
                     renderItem={({ info }) => null}
                     sections={AllMenu}
                     //refreshing={this.state.isLoading}
                 />
    
         )
     }
    
     _initItem(returnData) {
    
         var OAData = []
         var YXData = []
         var CGData = []
         var TJData = []
         //OA模块数据是固定的
         var data0 = { name: '外勤签到', img: Images.oaWQQD, onPress: () => alert('外勤签到') }
         var data1 = { name: '考勤打卡', img: Images.oaKQDK }
         var data2 = { name: '审批', img: Images.oaSP }
         var data3 = { name: '日志', img: Images.oaRZ }
         var data4 = { name: '任务', img: Images.oaRW }
         var data5 = { name: '公告', img: Images.oaGG }
         var data6 = { name: '证书', img: Images.oaZS }
         var data7 = { name: '印章', img: Images.oaYZ }
         var data8 = { name: '资产', img: Images.oaZC }
         var data9 = { name: '车辆', img: Images.oaCL }
         //把数据添加到办公子模块
         OAData.push(data0)
         OAData.push(data1)
         OAData.push(data2)
         OAData.push(data3)
         OAData.push(data4)
         OAData.push(data5)
         OAData.push(data6)
         OAData.push(data7)
         OAData.push(data8)
         OAData.push(data9)
    
         //循环找出拥有权限的模块
         for (var index = 0; index < returnData.length; index++) {
             var element = returnData[index];
             var menuId = element.menuId;
    
             if (menuId == 16) {
                 YXData.push({ name: '项目信息', img: Images.yxXMXY })
             }
             if (menuId == 17) {
                 YXData.push({ name: '营销任务', img: Images.yxYXRW })
             }
             if (menuId == 18) {
                 YXData.push({ name: '同行分析', img: Images.yxTHFX })
             }
             if (menuId == 19) {
                 YXData.push({ name: '投标管理', img: Images.yxTBGL })
             }
             if (menuId == 20) {
                 YXData.push({ name: '业绩PK', img: Images.yxYJPK })
             }
             if (menuId == 21) {
                 YXData.push({ name: '客户看板', img: Images.yxKHKB })
             }
             //采购
             if (menuId == 29) {
                 CGData.push({ name: '供应商', img: Images.cgGYS })
             }
             if (menuId == 30) {
                 CGData.push({ name: '物资采购', img: Images.cgWZCG })
             }
             if (menuId == 31) {
                 CGData.push({ name: '供应商评价', img: Images.cgGYSPJ })
             }
             if (menuId == 32) {
                 CGData.push({
                     name: '供应商往来', img: Images.cgGYSWL, onPress: () => alert('供应商往来')
                 })
             }
             //统计
             if (menuId == 8) {
                 TJData.push({ name: '管理统计', img: Images.tjGLTJ })
                 TJData.push({ name: '项目统计', img: Images.tjXMTJ })
             }
    
         }
    
         var OAMenu = { key: 0, title: '办公', data: OAData }//把办公子模块添加到办公模块
         var YXMenu = { key: 1, title: '营销', data: YXData }//把营销子模块添加到营销模块
         var CGMenu = { key: 2, title: '采购', data: CGData }//把采购子模块添加到采购模块
         var TJMenu = { key: 3, title: '统计', data: TJData }//把统计子模块添加到统计模块
         AllMenu.push(OAMenu);//讲办公添加到模块集合
         AllMenu.push(YXMenu);//讲营销添加到模块集合
         AllMenu.push(CGMenu);//讲采购添加到模块集合
         AllMenu.push(TJMenu);//讲统计添加到模块集合
    
     }
    }
    
     
    
     viewItemHeader: {
         flex: 1,
         backgroundColor: '#eeeeee',
         alignItems: 'center',
         paddingLeft: 20,
         paddingTop: 5,
         paddingBottom: 5,
     },
    
     viewRow: {
         // flexDirection: 'row',//设置横向布局 
         justifyContent: 'center',
         alignItems: 'center',
         width: ScreenWidth / 4,
         padding: 10,
     },
    
     imageItem: {
         height: 40,
         width: 40,
     },
    
     textItem: {
         textAlignVertical: 'center',
         color: '#5C5C5C',
         fontSize: 12,
     },
    
     flastList: {
     },
    })
    
    export default WorksView
    

3.总结
简书还是不智能,复制的代码 全部去掉看空格,我已经优化了一下,可能有的地方报错,需要补空格。
我在代码中没有用到SectionList中的keyExtractor属性,可能有些地方会报黄色警告,建议大家把文中的title字段作为key。
关于SectionList的属性请到ReactNative中文网 了解

条目层级

4.遇到的坑
4.1 如果把FlatList写到renderIten方法中会出现这样的情况


把标题写到renderSectionHeader中把FlatList写到renderItem中

会发现sectinItem不显示了

我猜测,这种情况是因为数据格式不对导致的,renderItem方法的参数是(info: {item: Item, index: number}) => ?所以参数全部都是数组中的对象信息(本文中是:{name:'营销任务',img:Images.yxYXRW})但是,FlatList需要的数据格式是整个条目的数组
4.2 如果直接在renderItem中返回子条目
如果按照常规的逻辑,我们大概会这样写,写出来的效果比较适合做通讯录等,每个item占用一行。而不能把item 进行Z型排列;这是系统默认的效果,我在这个基础上摸索了半天 没处理好,还请大神指点


header返回text,item中返回图标

效果是这样的

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 157,298评论 4 360
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 66,701评论 1 290
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 107,078评论 0 237
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 43,687评论 0 202
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,018评论 3 286
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,410评论 1 211
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,729评论 2 310
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,412评论 0 194
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,124评论 1 239
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,379评论 2 242
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 31,903评论 1 257
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,268评论 2 251
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 32,894评论 3 233
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,014评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,770评论 0 192
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,435评论 2 269
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,312评论 2 260

推荐阅读更多精彩内容

  • 本文纯原创,纯手打,请大神多多指教。转载请注明出处! react-native版本:0.48; 开发环境win10...
    冯涛_简书阅读 4,228评论 14 8
  • ¥开启¥ 【iAPP实现进入界面执行逐一显】 〖2017-08-25 15:22:14〗 《//首先开一个线程,因...
    小菜c阅读 6,191评论 0 17
  • 以下是常用的代码收集,学习用。转自豪情博客园 1. PC - js 返回指定范围的随机数(m-n之间)的公式 re...
    自由加咖啡阅读 971评论 0 1
  • AngularJS是什么?AngularJs(后面就简称ng了)是一个用于设计动态web应用的结构框架。首先,它是...
    200813阅读 1,517评论 0 3
  • 虽是阳春三月,春光还算明媚,但多愁善感的自己,尤其在那位亲戚回家之后更是抑郁难平。 其实亲戚关系甚远,甚至这只是第...
    爱米粒儿W阅读 235评论 0 0