React Native基础组件三

React Native系统组件三

1. FlatList 的使用与分析

一、功能简介

FlatList高性能的简单列表组件,支持下面这些常用的功能:

  • 完全跨平台。
  • 支持水平布局模式。
  • 行组件显示或隐藏时可配置回调事件。
  • 支持单独的头部组件。
  • 支持单独的尾部组件。
  • 支持自定义行间分隔线。
  • 支持下拉刷新。
  • 支持上拉加载。
  • 支持跳转到指定行(ScrollToIndex)。

二、属性说明

FlatList 有三个核心属性 data renderItem getItemLayout。它继承自 ScrollView 组件,所以拥有ScrollView 的属性和方法。

data

和 ListView 不同,它没有特殊的 DataSource 数据类型作为传入参数。它接收的仅仅只是一个 Array<object> 作为参数。
参数数组中的每一项,需要包含 key 值作为唯一标示。数据结构如下:

[
    {
        infoId: "1030296374794543105",
        price: "31万",
        warnType: 0,
        spdz: "",
        postDate: "08-17",
        state: 2,
        syncResult: "已同步2 失败0 同步中0",
        pic: "/p1/tiny/n_v2862e29d1f2854bbebf208d0a520591a9.jpg",
        title: "丰田 普拉多 2010款 4.0L 自动TX",
        age: "库龄35天",
        intention: 0
    }
]
renderItem

它接收一个函数作为参数,该函数返回一个 ReactElement。函数的第一个参数的 itemdata属性中的每个列表的数据( Array<object> 中的 object) 。这样就将列表元素和数据结合在一起,生成了列表,示例:

_renderItem({ item, index }) {
    let { infoId, title, pic, price, syncResult, postDate, age, state } = item;
    let url = "https://pic2.58cdn.com.cn" + pic;
    let icon = {
        2: require("./../img/yishou.png"),
        0: require("./../img/tuiku.png")
    };
    return (
        <TouchableHighlight style={styles.carList}>
            <View style={styles.carView}>
                {state == 1 ? null : 
                <Image style={styles.carIcon} source={icon[state]} />}
                <Image style={styles.carImg} source={{ uri: url }} />
                <View style={styles.carInfo}>
                    <Text numberOfLines={1} style={styles.carTitle}>
                        {title}
                    </Text>
                    <View style={styles.carTime}>
                        <Text style={styles.carDate}>{postDate}</Text>
                        <Text style={styles.carAge}>{age}</Text>
                    </View>
                    <View style={styles.carState}>
                        <Text style={styles.carPrice}>{price}</Text>
                        <Text style={styles.carStatus}>{syncResult}</Text>
                    </View>
                </View>
            </View>
        </TouchableHighlight>
    );
}
getItemLayout

可选优化项。但是实际测试中,如果不做该项优化,性能会差很多。所以强烈建议做此项优化!
如果不做该项优化,每个列表都需要事先渲染一次,动态地取得其渲染尺寸,然后再真正地渲染到页面中。

如果预先知道列表中的每一项的高度(ITEM_HEIGHT)和其在父组件中的偏移量(offset)和位置(index),就能减少一次渲染。这是很关键的性能优化点

getItemLayout={(data, index) =>
    // 90 是被渲染 item 的高度 ITEM_HEIGHT。
    ({ length: 90, offset: 90 * index, index })
}
extraData

如果有除data以外的数据用在列表中(不论是用在renderItem
还是Header或者Footer中),请在此属性中指定。同时此数据在修改时也需要先修改其引用地址(比如先复制到一个新的Object或者数组中),然后再修改其值,否则界面很可能不会刷新。(非常重要)

//确保state更新时列表及时更新
extraData={this.state}
ListEmptyComponent

列表为空时渲染该组件。可以是React Component, 也可以是一个render函数, 或者渲染好的element。

_renderEmptyView = () => {
    return (
        <View style={styles.listEmpty}>
            <Image style={styles.listEmptyImg} 
            source={require("./../img/norecord.png")} />
            <Text style={styles.listEmptyText}>您暂无符合此筛选条件的车源</Text>
        </View>
    );
};
keyExtractor

此函数用于为给定的item生成一个不重复的keyKey的作用是使React能够区分同类元素的不同个体,以便在刷新时能够确定其变化的位置,减少重新渲染的开销。若不指定此函数,则默认抽取item.key作为key值。若item.key也不存在,则使用数组下标。

keyExtractor={(item, index) => item.infoId}
下拉刷新、上拉加载

onRefresh={() => this._onRefresh()}
refreshing={this.state.isRefresh}
//加载更多
onEndReached={() => this._onLoadMore()}
//当列表被滚动到距离内容最底部不足onEndReachedThreshold的距离时调用
onEndReachedThreshold={0.1}

  • refreshing
    在等待加载新数据时将此属性设为true,列表就会显示出一个正在加载的符号。

  • onRefresh
    如果设置了此选项,则会在列表头部添加一个标准的RefreshControl
    控件,以便实现“下拉刷新”的功能。同时你需要正确设置refreshing
    属性。

  • onEndReachedThreshold
    决定当距离内容最底部还有多远时触发onEndReached
    回调。注意此参数是一个比值而非像素单位。比如,0.5表示距离内容最底部的距离为当前列表可见长度的一半时触发。

  • onEndReached
    当列表被滚动到距离内容最底部不足onEndReachedThreshold
    的距离时调用。

 constructor(props) {
        super(props);
        this.page = 1;
        this.state = {
            // 下拉刷新
            isRefresh: false,
            // 加载更多
            isLoadMore: false
        };
    }
 _onRefresh() {
    // 不处于 下拉刷新
    if (!this.state.isRefresh) {
        this.page = 1;
        let request = {
            cateId: 29,
            pageNum: this.page,
            pageSize: 20
        };
        request = this.mergeJson(request, this.state.filterVaule);
        this.getSourceList(request);
    }
}
getSourceList(request) {
    WBCST.getFetch("https://***.com/ershouche/stock/getList", request).then(
        (response) => {
            if (response && response.respCode == 0 && response.respData) {
                if (this.page == 1) {
                    //重新渲染
                    this.setState({
                        data: response.respData
                    });
                } else {
                    let loadMore = false;
                    if (response.respData.length < request.pageSize) {
                        //显示到底部了 没有更多数据了
                        loadMore = true;
                    }
                    this.setState({
                        //加载更多 这个变量不刷新
                        isLoadMore: loadMore,
                        //添加新数据源
                        data: this.state.data.concat(response.respData)
                    });
                }
            } else {
                // WBCST.loading({ state: "dismiss" });
                this.setState({
                    data: stockList.respData
                    // data: []
                });
                Toast.toast({ text: "当前网络不可用,请检查网络设置!", state: "error" });
            }
        }
    );
}

2. SectionList

  • 基础使用:sections、renderItem、keyExtractor
  • ScrollView属性:内容容器、滚动条、滚动监听、键盘模式等
  • 表头:ListHeaderComponent
  • 表尾:ListFooterComponent
  • 分组头部:renderSectionHeader
  • 分割线元素:ItemSeparatorComponent
  • 分组吸顶:stickySectionHeadersEnabled
  • 滚动api:scrollToLocation()
import { View, StyleSheet, SectionList, Text } from "react-native"
import { SectionData } from "../constants/Data";
import { useEffect, useRef } from "react";

export default () => {
    const renderItem = ({item, index, section}) => {
        return (
            <Text style={styles.txt}>{item}</Text>
        );
    };

    const renderSectionHeader = ({section}) => {
        return (
            <Text style={styles.sectionHeader}>{section.type}</Text>
        );
    };

    const sectionListRef = useRef(null);
    useEffect(() => {
        setTimeout(() => {
            sectionListRef.current.scrollToLocation({
                sectionIndex: 1,
                itemIndex: 2,
                // viewPosition: 0,
                
            });
        }, 2000);
    }, []);
    
    return (
        <SectionList
            ref={sectionListRef}
            style={styles.root}
            sections={SectionData}
            renderItem={renderItem}
            keyExtractor={(item, index) => `item-${index}`}
            renderSectionHeader={renderSectionHeader}
            stickySectionHeadersEnabled={true}
        >

        </SectionList>
    );
}

const styles = StyleSheet.create({
    root: {
        width: '100%',
        height: '100%',
        backgroundColor: '#f0f0f0',
    },
    txt: {
        fontSize: 20,
        height: 56,
        width: '100%',
        color: "#333",
        textAlignVertical: 'center',
        textAlign: 'center'
    },
    sectionHeader: {
        width: '100%',
        height: 36,
        backgroundColor: 'red',
        textAlign: 'center',
        fontSize: 22,
    }
});

3.Model

  • 控制显示:visible
  • 渲染内容:children
  • 安卓返回关闭:onRequestClose
  • 背景透明:transparent
  • 状态栏透明:statusBarTranslucent
  • 动画方式:animationType
  • 状态回调:onShow、onDismiss
  • 背景动画:伏笔
import { View, StyleSheet, Modal, Text, SectionList, Button, Image, TouchableOpacity } from "react-native"
import { SectionData } from "../constants/Data";
import { useRef, useState } from "react";
import close from "../assets/images/icon_close_modal.png"

export default () => {
    const [visible, setVisible] = useState(false);

    const showModal = () => {
        setVisible(true);
    }

    const hideModal = () => {
        setVisible(false);
    }



    const renderItem = ({ item, index, section }) => {
        return (
            <Text style={styles.txt}>{item}</Text>
        );
    };

    const renderSectionHeader = ({ section }) => {
        return (
            <View style={styles.sectionHeader}>
                <Text style={styles.sectionHeader}>{section.type}</Text>
            </View>


        );
    };

    const listHeader = () => {
        return (
            <View style={styles.listHeader}>
                <Text style={styles.listHeader}>
                    列表头部
                </Text>
                <TouchableOpacity
                    style={styles.iconButton}
                    onPress={() => {
                        hideModal()
                    }}
                >
                    <Image
                        source={close}
                        style={styles.icon}
                    />
                </TouchableOpacity>
            </View>

        );
    }

    return (
        <View style={styles.root}>
            <Button title="按钮" onPress={() => {
                showModal();
            }} />
            <Modal
                visible={visible}
                onRequestClose={() => {
                    hideModal();
                }}
                transparent={true}
                // statusBarTranslucent={true}
                animationType="slide"
                onShow={() => {
                    console.log('onShow...')
                }}
                onDismiss={() => {
                    //有问题,不回调
                    console.log('onDismiss...')
                }}
            >
                <View style={styles.blank}></View>
                <View style={styles.content}>
                    <SectionList
                        style={styles.sectionList}
                        sections={SectionData}
                        renderItem={renderItem}
                        keyExtractor={(item, index) => `item-${index}`}
                        renderSectionHeader={renderSectionHeader}
                        stickySectionHeadersEnabled={true}
                        ListHeaderComponent={listHeader}
                    >

                    </SectionList>
                </View>
            </Modal>
        </View>
    );
}

const styles = StyleSheet.create({
    root: {
        width: '100%',
        height: '100%',
        padding: 20,
    },
    content: {
        width: '100%',
        height: '90%',
        backgroundColor: "#ff000030"
    },
    sectionList: {
        width: '100%',
        height: '100%',
        backgroundColor: '#f0f0f0',
    },
    txt: {
        fontSize: 20,
        height: 56,
        width: '100%',
        color: "#333",
        textAlignVertical: 'center',
        textAlign: 'center'
    },
    sectionHeader: {
        width: '100%',
        height: 36,
        backgroundColor: 'red',
        textAlign: 'center',
        fontSize: 22,
        justifyContent: 'center'
    },
    blank: {
        width: '100%',
        height: '10%',
        backgroundColor: '#00000050'
    },
    icon: {
        width: 24,
        height: 24,
    },
    iconButton: {
        // width: 24,
        // height: 24,
        position: 'absolute',
        right: 16
    },
    listHeader: {
        width: '100%',
        height: 36,
        backgroundColor: 'yellow',
        textAlign: 'center',
        fontSize: 22,
        justifyContent: 'center',
        textAlignVertical: 'center'
    },
})

4.StatusBar:状态栏适配的难题交我

  • 内容深浅模式:barStyle
  • 背景颜色:backgroundColor
  • 动画切换:animated
  • 透明悬浮:translucent
  • 隐藏状态栏:hidden
  • api:setBackgroundColor()、setBarStyle()、setHidden()、setTranslucent()
<StatusBar 
                barStyle={"dark-content"}
                backgroundColor='white'
                // animated={true}
                // translucent={true}
                hidden={false}
            />
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。