React NativeREACT NATIVEReact Native

学习总结 ~ (三)React Native 初学 之 sec

2017-04-23  本文已影响12110人  白公子是猫奴

目的

今天我要实现一个 类似于 iOS 开发中带有分组的colllectionView 样式的布局, 每个section都要有个组头。

首先我们要先决定要使用什么控件。ScrollViewListView/FlatList还有SectionList都是可以选择的。

首先


首先第一步我们先把要显示的样式写好作为子控件, 把数据源整理好。

例一、
<SectionList
  renderItem={({item}) => <ListItem title={item.title} />}
  renderSectionHeader={({section}) => <H1 title={section.key} />}
  sections={[ // 不同section渲染相同类型的子组件
    {data: [...], key: ...},
    {data: [...], key: ...},
    {data: [...], key: ...},
  ]}
/>

例二、
<SectionList
  sections={[ // 不同section渲染不同类型的子组件
    {data: [...], key: ..., renderItem: ...},
    {data: [...], key: ..., renderItem: ...},
    {data: [...], key: ..., renderItem: ...},
  ]}
/>

sections 就是我们的数据源,每一个data 就是我们要用的item, renderItem就是你要显示的子控件哦。如果你每个组都复用一个子组件那就按照例一的结构, 如果你想要不同的组返回不同样式的子组件那就按照例二的结构返回不同的renderItem即可。
***这里提个醒, key一定要有, 不同的section 要设置不同的key才会渲染相应的section, 如果你key值都相同, 那可能会出现只显示一组数据的情况哦~ ***

下面来看看我的代码:
 <SectionList
                        renderItem={this._renderItem}
                        renderSectionHeader={this._renderSectionHeader}
                    sections={[ // 不同section渲染相同类型的子组件
                            { data: [{ title: this.state.appModel[0] }], key: this.state.groupsModel[0].title },
                            { data: [{ title: this.state.appModel[1] }], key: this.state.groupsModel[1].title },
                            { data: [{ title: this.state.appModel[2] }], key: this.state.groupsModel[2].title },
                            { data: [{ title: this.state.appModel[3] }], key: this.state.groupsModel[3].title },
                        ]}
                    />
1.png

这样有了最基础的样式, 四组纵向的列表, 但是我要横向的, 于是我要设置他的样式啦。

接下来


这里我添加两个属性:

  contentContainerStyle={styles.list}//设置cell的样式
  pageSize={4}  // 配置pageSize确认网格数量

const styles = StyleSheet.create({
    list: {
        //justifyContent: 'space-around',
        flexDirection: 'row',//设置横向布局  
        flexWrap: 'wrap',  //设置换行显示
        alignItems: 'flex-start',
        backgroundColor: '#FFFFFF'
    },
});

好啦, 让我们来看看效果。


2.png

😓这是什么鬼???
为什么它的组头也在左边 , 并且他的其他组数据都横着了, 对于小白我来说只有大写的懵~。不知道你们有没有遇到这种情况, 是什么原因导致的, 我很是困惑啊, 当我把

          renderSectionHeader={this._renderSectionHeader}

这行代码注掉的时候, 它的显示是正常的...


3.png

这就尴尬了...
它的每一个小方块是一个item,达不到我要的效果啊, 于是我决定换个思路, 谁让我是打不死的小白呢😝

重新来


我决定让每个section是一个item。在每个item上创建多个可点击的板块。show time ~ ~

 _renderItem = ({ item}) => (

        <View  style={styles.list}>
            {
                item.map((item, i) => this.renderExpenseItem(item, i))
            }
        </View>

    );

    renderExpenseItem(item, i) {

        return <TouchableOpacity key={i} onPress={() => this._pressRow(item)} underlayColor="transparent">
            <View style={styles.row}>
                <CellView source={item.img}></CellView>
            </View>
        </TouchableOpacity>;
    }

    _renderSectionHeader = ({ section }) => (
        <View style={{ flex: 1, height: 25 }}>
            <Text style={styles.sectionHeader} >{section.key}</Text>
        </View>
    );

    render() {
        return (
            <View style={{ flex: 1 }}>
                <Text style={styles.navigatorStyle}> 发现 </Text>
                <View style={{ flex: 1, backgroundColor: '#F7F6F8' }}>

                    <SectionList
                        renderItem={this._renderItem}
                        renderSectionHeader={this._renderSectionHeader}
                        showsVerticalScrollIndicator={false}
                        sections={ // 不同section渲染相同类型的子组件
                            this.state.dataSource
                        }
                    />
                </View>
            </View>
        );
    }
}

const styles = StyleSheet.create({
    list: {
        //justifyContent: 'space-around',
        flexDirection: 'row',
        flexWrap: 'wrap',
        alignItems: 'flex-start',
        backgroundColor: '#FFFFFF'
    },
    row: {
        backgroundColor: '#FFFFFF',
        justifyContent: 'center',
        width: (ScreenWidth - 1) / 4,
        height: (ScreenWidth - 1) / 4,
        alignItems: 'center',
    },
    sectionHeader: {
        marginLeft: 10,
        padding: 6.5,
        fontSize: 12,
        color: '#787878'
    },
});

这里的dataSource 我是在之前数据的基础上又包了一层[],然后在renderItem里做了map映射, 这样每个renderItem上返回了每一组我所需要的子组件。快来看看我的变化吧😊


4.png

肿么样, 达到效果了吧, 但是你有没有发现 底部为啥是黄色的?,我可没有去设置这么丑的颜色哦,其实它是提醒我们有不完美的地方, 下面就让我们解决一下这个不完美吧 。

最后解决问题


warning.png

最后让我们来解决问题。它警告我们每个item 要有不同的key ,还记不记得我上面的提醒,我也犯这个错误了。

把这个属性添加到      <SectionList/> 里面
       keyExtractor = {this._extraUniqueKey}   

         _extraUniqueKey(item ,index){
      return "index"+index+item;
}  

这是每个item要设置key, 同样每个子控件也不能放过, 一定要设置它的key, 要不然这个屎黄色一直伴着你 多烦~~~

最后看一下我最终的代码吧!

var Dimensions = require('Dimensions');//获取屏幕的宽高
var ScreenWidth = Dimensions.get('window').width;
var ScreenHeight = Dimensions.get('window').height;

// const AnimatedSectionList = Animated.createAnimatedComponent(SectionList);// 这个是创建动画
export default class Explore extends Component {

    constructor(props) {
        super(props);
        this.state = {
            appModel: null,
            groupsModel: null,
            dataSource: null,
        }
    }

    //Component挂载完毕后调用
    componentDidMount() {
        this.fetchData();
    }

    async fetchData() {
        try {
            let model = await NetFetch.post(_req_url_path, {

            });
            let apps = model.apps;
            let groups = model.groups;

            let data = [];
            for (let i = 0; i < model.groups.length; i++) {
                let row = [];
                for (let j = 0; j < model.apps.length; j++) {

                    if (model.groups[i].appIds.indexOf(model.apps[j].appId) >= 0) {
                        row.push(model.apps[j]);
                    }
                }

                data.push({ data: [row], key: model.groups[i].title });
            }
// 这里我重组了一下数据结构, 看没看见我在row外面又包了一层, 为了我循环创建每个section的子组件。

            this.setState({
                appModel: model.apps,
                groupsModel: model.groups,
                dataSource: data
            });

        } catch (error) {
            alert(error.msg);
        }
    }

    _renderItem = ({ item}) => (

        <View  style={styles.list}>
            {
                item.map((item, i) => this.renderExpenseItem(item, i))
            }
        </View>

    );

    renderExpenseItem(item, i) {

        return <TouchableOpacity key={i} onPress={() => this._pressRow(item)} underlayColor="transparent">
            <View style={styles.row}>
                <CellView source={item.img}></CellView>
            </View>
        </TouchableOpacity>;
    }


    _renderSectionHeader = ({ section }) => (
        <View style={{ flex: 1, height: 25 }}>
            <Text style={styles.sectionHeader} >{section.key}</Text>
        </View>
    );

    _listHeaderComponent() {
        return (
            <HeaderView integral={0}></HeaderView>
        );
    }

    _listFooterComponent() {
        return (
            <Text style={[styles.remark]}>*预期收益非平台承诺收益,市场有风险,投资需谨慎</Text>
        );
    }

    _pressRow(item) {
        this.props.navigator.pushTo(item.go)
    } 

    _extraUniqueKey(item ,index){
        return "index"+index+item;
   } 

    render() {
        if (!this.state.dataSource) {
            return (
                <View></View>
            );
        }

        return (
            <View style={{ flex: 1 }}>

                <Text style={styles.navigatorStyle}> 发现 </Text>

                <View style={{ flex: 1, backgroundColor: '#F7F6F8' }}>

                    <SectionList
                        contentInset={{top:0,left:0,bottom:49,right:0}}// 设置他的滑动范围
                        renderItem={this._renderItem}
                        ListFooterComponent={this._listFooterComponent}
                        ListHeaderComponent={this._listHeaderComponent}
                        renderSectionHeader={this._renderSectionHeader}
                        showsVerticalScrollIndicator={false}
                        keyExtractor = {this._extraUniqueKey}// 每个item的key
                        // contentContainerStyle={styles.list}
                        // horizontal={true}
                        // pageSize={4}  // 配置pageSize确认网格数量
                        sections={ // 不同section渲染相同类型的子组件
                            this.state.dataSource
                        }

                    />
                </View>
            </View>
        );
    }

}


const styles = StyleSheet.create({
    navigatorStyle: {
        height: 64,
        backgroundColor: '#FFFFFF',
        textAlign: 'center',
        paddingTop: 33.5,
        fontSize: 17,
        fontWeight: '600',
    },
    list: {
        //justifyContent: 'space-around',
        flexDirection: 'row',
        flexWrap: 'wrap',
        alignItems: 'flex-start',
        backgroundColor: '#FFFFFF'
    },
    row: {
        backgroundColor: '#FFFFFF',
        justifyContent: 'center',
        width: (ScreenWidth - 1) / 4,
        height: (ScreenWidth - 1) / 4,
        alignItems: 'center',
        // borderWidth: 0.5,
        // borderRadius: 5,
        // borderColor: '#E6E6E6'
    },
    sectionHeader: {
        marginLeft: 10,
        padding: 6.5,
        fontSize: 12,
        color: '#787878'
    },
    remark: {
        margin: 10,
        fontSize: 10,
        color: '#D2D2D2',
        marginBottom: 10,
        alignSelf: 'center',
    },
});

看下最终效果图吧


完美.jpg

最最后总结一下在开发中遇到的疑难杂症还有sectionList的重要属性。


???.png

不知道你有没有遇见这个问题, 看起来很简单, 应该是我没有引入Text组件, 但是我确实引入了。最终发现这个问题竟是因为我有段代码是这样写的

           <Image> source={require('../../assets/image/deadline.png')} style={styles.iconStyle} </Image>
                            <Text style={styles.userNameStyle}>赚积分,换好礼!</Text>

不知道你有没有发现错误, 由于习惯我<Image>组件写成<Image></Image>,Image是自封闭标签所以

           <Image source={require('../../assets/image/deadline.png')} style={styles.iconStyle} />
                            <Text style={styles.userNameStyle}>赚积分,换好礼!</Text>

这样问题就解决了, 但是我不清楚它为啥会报这样的错,反正开发中总是会出现一些不知所以的错, 所以平时写代码的时候不断总结起来就好啦...

SectionList 属性

最后再提醒一下不要忘了key key key 哦 。
欢迎大家给提意见哦, 里面还是有一些不懂与不足的地方,快用你的见解砸我吧 😘

上一篇 下一篇

猜你喜欢

热点阅读