滚动本机事件更新所有相同类型的包装器组件

时间:2019-03-24 13:27:46

标签: react-native react-navigation expo

我在react导航库中使用了包装器平面列表组件。 该组件位于不同的stacknavigation选项卡中,用于处理标题的动画。

import React, { Component } from "react";
import { Constants } from 'expo';
// import PropTypes from "prop-types";
import {
  Animated,
  Dimensions,
  // PanResponder,
  // Platform,
  // ScrollView,
  StyleSheet,
  FlatList,
  // ScrollView,
  // StatusBar,
  // Text,
  // TouchableWithoutFeedback,
  // View
} from "react-native";
// import Icon from "react-native-vector-icons/Ionicons";

// Get screen dimensions
const { width, height } = Dimensions.get("window");

const AnimatedFlatList = Animated.createAnimatedComponent(FlatList);
const HEADER_HEIGHT= 40;
const FILTER_HEIGHT= 50;
const STATUS_BAR_HEIGHT = Constants.statusBarHeight;
const NAVBAR_HEIGHT = HEADER_HEIGHT+FILTER_HEIGHT-2;
const scrollAnim = new Animated.Value(0);
const offsetAnim = new Animated.Value(0);

export default class AnimatedFlatListComp extends React.PureComponent {
  // Define state
  state = {
    scrollAnim,
    offsetAnim,
    clampedScroll: Animated.diffClamp(
      Animated.add(
        scrollAnim.interpolate({
          inputRange: [0, 1],
          outputRange: [0, 1],
          extrapolateLeft: 'clamp',
        }),
        offsetAnim,
      ),
      0,
      // NAVBAR_HEIGHT - STATUS_BAR_HEIGHT,
      HEADER_HEIGHT //i mede this one cuz the code abode not work is the value 40
    ),
  };

  componentWillUnmount() {
    console.log('smontoooo');
    // this._isMounted = false;
    // Don't forget to remove the listeners!
    // this.state.scrollAnim.removeAllListeners();
    // this.state.offsetAnim.removeAllListeners();
    this._disableListener();
  }

  componentDidMount() {
    this._clampedScrollValue = 0;
    this._offsetValue = 0;
    this._scrollValue = 0;
    this._enableLister()
    this._handleScroll()
  }

  _onMomentumScrollBegin = () => {
    console.log('_onMomentumScrollBegin');
      clearTimeout(this._scrollEndTimer);
  }

  _onScrollEndDrag = () => {
    this._scrollEndTimer = setTimeout(this._onMomentumScrollEnd, 250);
  }

  _onMomentumScrollEnd = () => {
    console.log('_onMomentumScrollEnd');
    console.log(this._scrollValue, NAVBAR_HEIGHT, this._clampedScrollValue, (NAVBAR_HEIGHT - STATUS_BAR_HEIGHT) / 2);
    const toValue = this._scrollValue > NAVBAR_HEIGHT &&
      this._clampedScrollValue > (NAVBAR_HEIGHT - STATUS_BAR_HEIGHT) / 2
      ? this._offsetValue + NAVBAR_HEIGHT
      : this._offsetValue - NAVBAR_HEIGHT;

    Animated.timing(this.state.offsetAnim, {
      toValue,
      duration: 350,
      useNativeDriver: true,
    }).start();
  }

  _handleScroll = () => this.props._handleScroll(this.state.clampedScroll)

  // _handleScroll = event => {
  //   const { y } = event.nativeEvent.contentOffset;
  //   // // console.log(y);
  //   this.setState({ scrollOffset: y }, () => {
  //     this.props._handleScroll(this.state.clampedScroll)
  //   });
  //
  // };

  _scrollToTop = () => {
    console.log('_scrollToTop');
    if (!!this.flatListRef) {
      // this.flatListRef.getNode().scrollTo({ y: 0, animated: true });
      this.flatListRef.getNode().scrollToOffset({ offset: 0, animated: true });
    }
  };

  _enableLister = () => {
    // this._firstMountFunction();
    this.state.scrollAnim.addListener(({ value }) => {
      // This is the same calculations that diffClamp does.
      const diff = value - this._scrollValue;
      this._scrollValue = value;
      this._clampedScrollValue = Math.min(
        Math.max(this._clampedScrollValue + diff, 0),
        NAVBAR_HEIGHT - STATUS_BAR_HEIGHT,
      );
    });
    this.state.offsetAnim.addListener(({ value }) => {
      this._offsetValue = value;
    });
  }

  _disableListener = () => {
    this.state.scrollAnim.removeAllListeners();
    this.state.offsetAnim.removeAllListeners();
  }

  _keyExtractor = (item, index) => index.toString();

  // _onScroll = event => {
  // 
  // }

  render() {

    return (
      <AnimatedFlatList
        {...this.props}
        ref={(ref) => { this.flatListRef = ref; }}
        showsVerticalScrollIndicator={false}
        onScroll={Animated.event(
          [{nativeEvent: {contentOffset: {y: this.state.scrollAnim}}}],
          {
            useNativeDriver: true,
            // listener: this._handleScroll
          },
        )}
        // onScroll={this._onScroll}
        removeClippedSubviews={true}
        keyExtractor={this._keyExtractor}
        onMomentumScrollBegin={this._onMomentumScrollBegin}
        onMomentumScrollEnd={this._onMomentumScrollEnd}
        onScrollEndDrag={this._onScrollEndDrag}
        scrollEventThrottle={1}
      />

    );
  }
}

这是父母

_handleScroll = clampedScroll => this.setState({ clampedScroll: clampedScroll })
render(){
const { clampedScroll } = this.state;
      //
      const navbarTranslate = clampedScroll.interpolate({
        inputRange: [0, NAVBAR_HEIGHT - STATUS_BAR_HEIGHT],
        outputRange: [0, -(NAVBAR_HEIGHT - STATUS_BAR_HEIGHT)],
        extrapolate: 'clamp',
      });
return (
          <AnimatedFlatList
            // debug={true}
            ref={(ref) => { this.flatListRef = ref; }}
            maxToRenderPerBatch={4}
            contentContainerStyle={{
              paddingTop: NAVBAR_HEIGHT+STATUS_BAR_HEIGHT,
            }}
            data={this.state.dataSource}
            renderItem={
              ({item, index}) =>
                <CardAgenda
                  item={JSON.parse(item.JSON)}
                  ChangeSelectedEvent={this.ChangeSelectedEvent}
                  colorTrail={JSON.parse(item.colorTrail)}
                  // _sendBackdata={this._getChildrenCategoryData}
                  searchData={JSON.parse(item.searchData)}
                  NumAncillary={item.NumAncillary}
                  indexItinerary={item.id}
                  index={index}
                />
            }
            ListEmptyComponent={this._emptyList}
            ItemSeparatorComponent={() => <View style={{width: width-40, backgroundColor: 'rgba(0,0,0,0.1)', height: 1, marginTop: 20, marginLeft: 20, marginRight: 20}}/>}
            _handleScroll={this._handleScroll}
          />
)}

它工作正常,但是onscroll事件触发所有包装程序的this.state.scrollAnim变量。 我的意思是,如果我向上滚动第一个AnimatedFlatList,则标题会上升,但新导航页面中的另一个标题也会上升。

正确的行为必须是所有标头必须独立于自己的平面列表。

预先感谢

1 个答案:

答案 0 :(得分:1)

这是因为在创建动画的Values obj时要建立对状态的引用。您不应将它们保留为类边界之外的常量。

尝试删除以下常量。

const scrollAnim = new Animated.Value(0);
const offsetAnim = new Animated.Value(0);

然后在构造函数中定义它们。

 export default class AnimatedFlatListComp extends React.PureComponent {
  constructor(props){
   super(props);
   this.scrollAnim = new Animated.Value(0);
   this.offsetAnim = new Animated.Value(0);
   // Define state
   state = {
        scrollAnim: this.scrollAnim,
        offsetAnim:  this.offsetAnim,
        clampedScroll: Animated.diffClamp(
          Animated.add(
            this.scrollAnim.interpolate({
              inputRange: [0, 1],
              outputRange: [0, 1],
              extrapolateLeft: 'clamp',
            }),
           this.offsetAnim,
          ),
        0,
        // NAVBAR_HEIGHT - STATUS_BAR_HEIGHT,
        HEADER_HEIGHT //i mede this one cuz the code abode not work is 
        the value 40
        ),
      };
    }