У меня есть компонент плоского списка оболочки, используемый в библиотеке реагирующей навигации.
Этот компонент находится на другой вкладке навигации по стеку для обработки анимации заголовка.
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, заголовок поднимается, но и другой заголовок на новой навигационной странице повышается.
Правильным поведением должно быть то, что весь заголовок должен быть независимым от собственного плоского списка.
Заранее спасибо