react-native用flatlist实现抖音上下切换效果

2019-04-28  本文已影响0人  张大娃创业笔记

基本实现有待进一步优化,先记录在这里

'use strict';
import React, { Component } from 'react';
import { View, Animated, Text, StyleSheet, Image, Dimensions, TouchableOpacity, FlatList, PanResponder } from 'react-native';
import px2dp from '../../utils/px2dp'

const { width, height } = Dimensions.get("window");

export default class HousePage extends Component {
    static navigationOptions = ({ navigation }) => {
        const { params } = navigation.state;
        //console.warn(navigation);
        return {
            header: null
        }
    };
    _flatList;
    constructor(props) {
        super(props);
        this.state = {
            sports: new Animated.Value(-height), // 设置初始值
            listlen:4
        }
        this.startTimestamp = 0 // 拖拽开始时间戳(用于计算滑动速度)
        this.endTimestamp = 0 // 拖拽结束时间戳用于计算滑动速度)
        this.page = 0 // 首次展示第一条数据(page 最小值为0,即从0开始,1为第二个条目)
    }
    componentWillMount() {
        this.panResponder()
    }
    panResponder() {
        this._panResponder = PanResponder.create({
            // 要求成为响应者:
            onStartShouldSetPanResponder: (evt, gestureState) => true,
            onStartShouldSetPanResponderCapture: (evt, gestureState) => true,
            onMoveShouldSetPanResponder: (evt, gestureState) => true,
            onMoveShouldSetPanResponderCapture: (evt, gestureState) => true,

            onPanResponderGrant: (evt, gestureState) => {
                // 开始手势操作。给用户一些视觉反馈,让他们知道发生了什么事情!
                // 滑动开始,记录时间戳
                this.startTimestamp = evt.nativeEvent.timestamp
            },
            onPanResponderMove: (evt, gestureState) => {
                // 最近一次的移动距离为gestureState.move{X,Y}
                // 从成为响应者开始时的累计手势移动距离为gestureState.d{x,y}
                // 滑动纵向距离
                let y = gestureState.dy
                //console.warn(y)
                // 实时改变滑动位置
                if (y > 0) {
                    this._flatList.scrollToOffset({animated: true,offset: this.page*height-y});
                } else if(y<0){
                    y = Math.abs(y)
                    this._flatList.scrollToOffset({animated: true, offset: this.page * height+y});
                }
            },
            onPanResponderRelease: (evt, gestureState) => {
                // 用户放开了所有的触摸点,且此时视图已经成为了响应者。
                // 一般来说这意味着一个手势操作已经成功完成。
                // 滑动结束时间戳
                this.endTimestamp = evt.nativeEvent.timestamp
                // 滑动距离,根据滑动距离与时间戳计算是否切换到下一个条目
                let y = gestureState.dy
                console.warn(gestureState)
                if (y > 0) {
                    // 滑动距离大于屏幕1半,开启动画,滑动到下一个界面,或者滑动速度很快,并且滑动距离大于20,也滑动到下一个条目
                    if (y > height / 2 || (this.endTimestamp - this.startTimestamp < 300 && y > 20)) {
                        if(this.page!=0){
                            this.page -= 1
                        }
                    }
                    this._flatList.scrollToIndex({ animated: true, index: this.page });
                } else if (y < 0) {
                    y = Math.abs(y)
                    // 滑动距离大于屏幕1半,开启动画,滑动到下一个界面,或者滑动速度很快,并且滑动距离大于20,也滑动到下一个条目
                    if (y > height / 2 || (this.endTimestamp - this.startTimestamp < 300)) {
                        if(this.state.listlen!==(this.page+1)){
                            this.page += 1
                        }
                    }
                    this._flatList.scrollToIndex({ animated: true, index: this.page });
                }
            },
            onPanResponderTerminate: (evt, gestureState) => {
                // 另一个组件已经成为了新的响应者,所以当前手势将被取消。
            },
            onShouldBlockNativeResponder: (evt, gestureState) => {
                // 返回一个布尔值,决定当前组件是否应该阻止原生组件成为JS响应者
                // 默认返回true。目前暂时只支持android。
                return false;
            },
        });
    }
    _renderItem(item, index) {
        return (
            <View key={index} style={{ width: width, height: height }}
                {...this._panResponder.panHandlers}
            >
                <Image
                    style={styles.backgroundImage}
                    source={{ uri: item.uri }}
                />
            </View>
        )
    }
    render() {
        return (
            <View style={{ flex: 1, justifyContent: 'flex-start', backgroundColor: '#959595' }}>
                <FlatList
                    ref={(flatList) => this._flatList = flatList}
                    data={[{ key: 'a', uri: 'https://ss1.bdstatic.com/70cFuXSh_Q1YnxGkpoWK1HF6hhy/it/u=3253084641,1582561932&fm=26&gp=0.jpg' }, { key: 'b', uri: 'https://ss1.bdstatic.com/70cFvXSh_Q1YnxGkpoWK1HF6hhy/it/u=293994202,1923937239&fm=26&gp=0.jpg' },{ key: 'c', uri: 'https://ss1.bdstatic.com/70cFuXSh_Q1YnxGkpoWK1HF6hhy/it/u=3253084641,1582561932&fm=26&gp=0.jpg' }, { key: 'd', uri: 'https://ss1.bdstatic.com/70cFvXSh_Q1YnxGkpoWK1HF6hhy/it/u=293994202,1923937239&fm=26&gp=0.jpg' }]}
                    renderItem={({ item, index }) => this._renderItem(item, index)}
                    getItemLayout={(data, index) => (
                        { length: height, offset: height * index, index }
                    )}
                    scrollEnabled={false}
                />
                <View style={{ position: 'absolute', zIndex: 10000, bottom: 0, left: 0, right: 0, flexDirection: 'row', alignItems: 'center', justifyContent: 'space-around', height: px2dp(98), borderTopColor: '#e6e6e6', borderTopWidth: 1, backgroundColor: 'rgba(0,0,0,0,0.5)' }}>
                    <TouchableOpacity onPress={() => this.props.navigation.navigate('Home')}>
                        <View style={{ flexDirection: 'column', justifyContent: 'center', alignItems: 'center' }}>
                            <Image
                                source={require('../../assets/images/icon_tabnav-4-1.png')}
                                style={{ width: px2dp(48), height: px2dp(42), resizeMode: 'contain' }}
                            />
                            <Text style={{ fontSize: px2dp(20), marginTop: px2dp(8), color: '#dbdbdb' }}>首页</Text>
                        </View>
                    </TouchableOpacity>
                    <View style={{ flexDirection: 'column', justifyContent: 'center', alignItems: 'center' }}>
                        <Image
                            source={require('../../assets/images/icon_tabnav-1-1.png')}
                            style={{ width: px2dp(48), height: px2dp(42), resizeMode: 'contain' }}
                        />
                        <Text style={{ fontSize: px2dp(20), marginTop: px2dp(8), color: 'white' }}>房源</Text>
                    </View>
                    <TouchableOpacity onPress={() => this.props.navigation.navigate('Take')}>
                        <View style={{ flexDirection: 'column', justifyContent: 'center', alignItems: 'center' }}>
                            <Image
                                source={require('../../assets/images/icon_tabnav-3-1.png')}
                                style={{ width: px2dp(48), height: px2dp(42), resizeMode: 'contain' }}
                            />
                            <Text style={{ fontSize: px2dp(20), marginTop: px2dp(8), color: '#dbdbdb' }}>拍摄</Text>
                        </View>
                    </TouchableOpacity>
                    <TouchableOpacity onPress={() => this.props.navigation.navigate('Follow')}>
                        <View style={{ flexDirection: 'column', justifyContent: 'center', alignItems: 'center' }}>
                            <Image
                                source={require('../../assets/images/icon_tabnav-2-1.png')}
                                style={{ width: px2dp(48), height: px2dp(42), resizeMode: 'contain' }}
                            />
                            <Text style={{ fontSize: px2dp(20), marginTop: px2dp(8), color: '#dbdbdb' }}>关注</Text>
                        </View>
                    </TouchableOpacity>
                    <TouchableOpacity onPress={() => this.props.navigation.navigate('User')}>
                        <View style={{ flexDirection: 'column', justifyContent: 'center', alignItems: 'center' }}>
                            <Image
                                source={require('../../assets/images/icon_tabnav-5-1.png')}
                                style={{ width: px2dp(48), height: px2dp(42), resizeMode: 'contain' }}
                            />
                            <Text style={{ fontSize: px2dp(20), marginTop: px2dp(8), color: '#dbdbdb' }}>我的</Text>
                        </View>
                    </TouchableOpacity>
                </View>
            </View >
        )
    }

}

const styles = StyleSheet.create({
    backgroundImage: {
        width,
        height
    },
});
上一篇下一篇

猜你喜欢

热点阅读