RN-实现抖音切换视频效果

2020-09-29  本文已影响0人  精神病患者link常

实现效果
1、上下滑动切换
2、 左滑动弹出列表,右滑动取消列表
3、加载更多、刷新

实现效果

思路

<View 手势(上滑动、下滑动、左滑动(弹出RightView))>
  <FlatList 禁止滚动 renderItem的高和宽和屏幕一样/>
</View>
<RightView 手势(只判断右滑动,用于返回)/>

通过滑动的x、y判断是上下滑动还是左右滑动

1.上下滑动

滑动中:通过 flatList.scrollToOffset 设置flatList的滚动位置
滑动结束:通过判断滑动的位置 || 滑动的速度 进行切换页面

  1. 滑动距离超过屏幕的1/4
  2. 滑动结束时间 - 滑动开始时间 < 300 && 滑动距离超过 50

再通过flatList.scrollToIndex设置flatList的滚动位置

2.左滑动,显示RightView.RightView position:'absolute' left: screenWidth

左滑动过程中setState left 的值,配合LayoutAnimation实现RightView弹出

3.下拉刷新,上拉加载

下拉刷新:第一页的位置,下拉超过30,则显示ListHeaderComponent
上拉加载:最后一页的位置,上拉超过30,则显示loadingComponent

RightView 手势

右滑动:setState left 的值,配合LayoutAnimation实现RightView消失

具体代码

index.,js

class ClassName extends React.Component {

    constructor(props) {
        super(props);
        this.props.navigation.setOptions({ headerShown: false })
        if (Platform.OS === 'android') {
          UIManager.setLayoutAnimationEnabledExperimental && UIManager.setLayoutAnimationEnabledExperimental(true)
        }
        this.state = {
          list: [1,2,3,4,5],
          cityListLeft:width,
          refreshing:false,
          isLoading:false
      }
      this.startTime = 0 // 滚动开始时间
      this.endTime = 0 // 滚动结束时间 ,用于计算滚动的速度(结束时间 - 开始时间,时间越短,滚动速度越快)
      this.page = 0 // 当前页

      // 根据滑动的距离 或者 滑动的速度且滑动距离大于50,判断是否切换

      // 纵向滚动切换页面条件一
      this.minSlideDistance = 50 // 滚动时间符合要求时的最小滚动距离
      this.maxSlideTime = 300 // 最大的滚动时间,
      
      // 条件二
      this.minSlideScaleY = 1 / 4 // 最小的滚动比例

      // 横向滚动显示页面
      this.minSlideScaleX = 1 / 4 // 最小的拖动比例

      this.isRefresh = false // 用于判断是否处于下拉刷新中,减少下拉过程总多次setState
      this.isLoadMore = false // 用于判断是否处于上拉加载更多中,减少上拉过程总多次setState

      // 初始化时定义,不要在render中定义
      this.viewabilityConfig = {viewAreaCoveragePercentThreshold: 80}

      this.panResponder = PanResponder.create({
        // 要求成为响应者,防止弹出的页面中按钮不可点击
       onStartShouldSetPanResponder: (evt, gestureState) => {
          if (Math.abs(gestureState.dx) > 10 || Math.abs(gestureState.dy) > 10){
            return true
          }
          return false
        },
        onStartShouldSetPanResponderCapture: (evt, gestureState) => {

          if (Math.abs(gestureState.dx) > 10 || Math.abs(gestureState.dy) > 10){
            return true
          }
          return false
        },
        onMoveShouldSetPanResponder: (evt, gestureState) => {
          if (Math.abs(gestureState.dx) > 10 || Math.abs(gestureState.dy) > 10){
            return true
          }
          return false
        },
        onMoveShouldSetPanResponderCapture: (evt, gestureState) => {

          if (Math.abs(gestureState.dx) > 10 || Math.abs(gestureState.dy) > 10){
            return true
          }
          return false
        },
        onPanResponderGrant: (evt, gestureState) => {
          // 滑动开始时间
          this.startTime = evt.nativeEvent.timestamp
        },
        onPanResponderMove: (evt, gestureState) => {
          let y = gestureState.dy
          let x = gestureState.dx

          if (Math.abs(x) > Math.abs(y)){
            // 横向滑动
            if (Math.abs(x) > 30){
              if (x > 0){
                // 向右
                if (this.state.cityListLeft == width){
                }else {
                  this.setState({
                    cityListLeft:x
                  })
                }
              }else {
                // 向左
                if (this.state.cityListLeft == 0){
                }else {
                  x = Math.abs(x)
                  this.setState({
                    cityListLeft:width - x
                  })
                }
              }
            }
          }else {
            // 纵向滑动
            if (Math.abs(y) > 30){
              if (y > 0) {
                // 第一页,下拉加载更多
                if (this.page == 0){
                  if (!this.isRefresh){
                    this.setState({
                      refreshing:true,
                      isLoading:true
                    })
                    this.isRefresh = true
                    // 请求接口
                    this.onRefresh()
                  }
                  this.flatList.scrollToOffset({animated: false,offset: -y})
                }else {
                  this.flatList.scrollToOffset({animated: false,offset: this.page*height-y})
                }
              } else{
                y = Math.abs(y)
                if (this.page == this.state.list.length - 1){
                  // 最后一页,上拉刷新
                  if (!this.isLoadMore){
                    this.setState({
                      isLoading:true,
                    })
                    this.isLoadMore = true
                    this.onEndReached()
                  }
                }
                this.flatList.scrollToOffset({animated: false, offset: this.page * height + y})
              }
            }
          }
        },
        onPanResponderRelease: (evt, gestureState) => {
          this.endTime = evt.nativeEvent.timestamp
          let y = gestureState.dy
          let x = gestureState.dx
          if (Math.abs(x) > Math.abs(y)){
            // 纵向重置状态
            this.flatList.scrollToIndex({ animated: true, index: this.page });
            // 横向滑动
            if (x > 0){
              if (this.state.cityListLeft == width){
              }else {
                if (x > width * this.minSlideScaleX){
                  this.setState({
                    cityListLeft:width
                  })
                }else {
                  this.setState({
                    cityListLeft:0
                  })
                }
                LayoutAnimation.easeInEaseOut();
              }
            }else {
              if (this.state.cityListLeft == 0){
              }else {
                if (Math.abs(x) > width * this.minSlideScaleX){
                  this.setState({
                    cityListLeft:0
                  })
                }else {
                  this.setState({
                    cityListLeft:width
                  })
                }
                LayoutAnimation.easeInEaseOut();
              }
            }
          }else {
            // 纵向滑动
            // 横向重置状态
            this.setState({
              cityListLeft:width
            })
            if (y > 0) {
              // 向上
              if (y > height * this.minSlideScaleY || (this.endTime - this.startTime < this.maxSlideTime && y > this.minSlideDistance)) {
                if(this.page != 0){
                  this.page -= 1
                }
              }
              this.flatList.scrollToIndex({ animated: true, index: this.page });
            } else if (y < 0) {
              // 向下
              y = Math.abs(y)
              if (y > height * this.minSlideScaleY || (this.endTime - this.startTime < this.maxSlideTime && y > this.minSlideDistance)) {
                if(this.state.list.length != this.page + 1){
                  this.page += 1
                }
              }
              this.flatList.scrollToIndex({ animated: true, index: this.page });
            }
          }
        },
        onPanResponderTerminate: (evt, gestureState) => {
        },
        onShouldBlockNativeResponder: (evt, gestureState) => {
          return false;
        },
      });

      this.cityPanResponder = PanResponder.create({
        // 要求成为响应者:
        onStartShouldSetPanResponder: (evt, gestureState) => true,
        onStartShouldSetPanResponderCapture: (evt, gestureState) => true,
        onMoveShouldSetPanResponder: (evt, gestureState) => true,
        onMoveShouldSetPanResponderCapture: (evt, gestureState) => true,

        onPanResponderGrant: (evt, gestureState) => {
        },
        onPanResponderMove: (evt, gestureState) => {
          let x = gestureState.dx
            // 横向滑动
            if (Math.abs(x) > 30){
              if (x > 0){
                // 向右
                this.setState({
                  cityListLeft:x
                })
              }
            }
        },
        onPanResponderRelease: (evt, gestureState) => {
          this.endTime = evt.nativeEvent.timestamp
          let x = gestureState.dx
          // 横向滑动
          if (x > 0){
            console.log('向右');
            if (x > width * this.minSlideScaleX){
              this.setState({
                cityListLeft:width
              })
            }else {
              this.setState({
                cityListLeft:0
              })
            }
            LayoutAnimation.easeInEaseOut();
          }
        },
        onPanResponderTerminate: (evt, gestureState) => {
        },
        onShouldBlockNativeResponder: (evt, gestureState) => {
          return false;
        },
      });
    }

    componentWillUnmount() {

    }

    componentDidMount(){
   
    }
    onEndReached=()=>{
      console.log('onEndReached');
      setTimeout(() => {
        this.setState({
          isLoading:false,
        })
        this.isLoadMore = false
      }, 1500);
    }

    onRefresh=()=>{
      // 请求接口数据,刷新
      setTimeout(() => {
        this.setState({
          refreshing:false,
          isLoading:false
        })
        this.isRefresh = false
      }, 1500);
    }
    // 不要在render中定义
    onViewableItemsChanged=(info)=>{
      console.log('infoinfoinfoinfo===',info);
      if(info.viewableItems.length > 0){
        // 显示了新的item
      }
    }

    render() {
        return Render.render.call(this);
    }
}

const mapStateToProps = state => {
  return {
    userInfo: state.userInfo,
    globalInfo: state.globalInfo,
  }
};

const mapDispatchToProps = dispatch => ({
    getUserInfo: userInfo => dispatch({type: ActionTypes.GET_USERINFO, payload: {userInfo}}),
    loginSuccess: globalInfo => dispatch({type: ActionTypes.LOGIN_SUCCESS, payload: {globalInfo}}),
    setWalletMine: wallet => dispatch({type: ActionTypes.SET_WALLET_MINE, payload: wallet}),

});
export default connect(mapStateToProps, mapDispatchToProps)(FishpondList);

render.js

<View style={styles.mainView} {...this.panResponder.panHandlers}>
  <FlatList   ref={ref=>this.flatList = ref}
              data={this.state.list}
              renderItem={({ item, index }) => {
                return <View key={index}>
                  <View style={[styles.item,{
                    backgroundColor:`rgb(${Math.random() * 255},${Math.random() * 255},${Math.random() * 255})`
                  }]}>
                    <Text style={{color:'#fff',fontSize:70}}>{index+1}</Text>
                  </View>
                </View>
              }}
              ListHeaderComponent={this.state.refreshing ?<ListHeaderComponent/> : <View/>}
              getItemLayout={(data, index) => (
                { length: styles.item.height, offset: styles.item.height * index, index }
              )}
              scrollEnabled={false}
              onViewableItemsChanged={this.onViewableItemsChanged}
              viewabilityConfig={this.viewabilityConfig}
              showsVerticalScrollIndicator={false}
            />
</View>
<RightView panResponder={this.cityPanResponder} left={this.state.cityListLeft}/>
上一篇下一篇

猜你喜欢

热点阅读