React Native开启useNativeDriver时,如何实时记录Animated ScrollView的contentOffset.y值更新?
Hey there! Let's work through how to get the updated scroll Y value from your Animated ScrollView when using useNativeDriver: true—I'll walk you through a few solid solutions, plus explain why your initial attempts didn't work.
Solution 1: Fix the Animated.Value.addListener Approach (Class Components)
Your initial code was on the right track, but you were accessing the wrong value and not handling the listener properly. When useNativeDriver: true, the Animated.Value's internal _value property (which you tried to print) doesn't update on the JS thread (since animations run natively). Instead, use the value passed to your listener callback, and make sure to clean up the listener to avoid memory leaks.
Here's the corrected code:
class YourScrollComponent extends React.Component { state = { y: new Animated.Value(0) }; _scrollListener = null; _currentScrollY = 0; componentDidMount() { // Save the listener subscription so we can remove it later this._scrollListener = this.state.y.addListener(({ value }) => { this._currentScrollY = value; console.log("Updated scroll Y:", value); // Print immediately when the value changes }); } componentWillUnmount() { // Clean up the listener when the component unmounts if (this._scrollListener) { this.state.y.removeListener(this._scrollListener); } } render() { // If you need to use the value elsewhere in your component, use this._currentScrollY return ( <Animated.ScrollView scrollEventThrottle={16} showsVerticalScrollIndicator={false} onScroll={Animated.event( [{ nativeEvent: { contentOffset: { y: this.state.y } } }], { useNativeDriver: true } )} > {/* Your scrollable content goes here */} </Animated.ScrollView> ); } }
Solution 2: Add a Listener Directly to Animated.event
This is a more concise approach—you can attach a listener function directly in the options object of Animated.event, which fires every time the scroll event triggers (even with useNativeDriver: true).
Code example:
class YourScrollComponent extends React.Component { state = { y: new Animated.Value(0) }; _onScrollUpdate = (event) => { const scrollY = event.nativeEvent.contentOffset.y; console.log("Scroll Y value:", scrollY); // If you need to sync this value to other parts of your app, you can update state here too // this.setState({ currentScrollY: scrollY }); }; render() { return ( <Animated.ScrollView scrollEventThrottle={16} showsVerticalScrollIndicator={false} onScroll={Animated.event( [{ nativeEvent: { contentOffset: { y: this.state.y } } }], { useNativeDriver: true, listener: this._onScrollUpdate, // Attach your listener here } )} > {/* Your scrollable content goes here */} </Animated.ScrollView> ); } }
Solution 3: Functional Component Alternative (with Reanimated)
If you ever switch to functional components, using React Native Reanimated v2+ gives you a more efficient way to handle scroll events with native drivers. Here's how that looks:
import Animated, { useAnimatedScrollHandler, useSharedValue, runOnJS } from 'react-native-reanimated'; function YourFunctionalScrollComponent() { const scrollY = useSharedValue(0); const scrollHandler = useAnimatedScrollHandler({ onScroll: (event) => { scrollY.value = event.contentOffset.y; // Since this runs on the native thread, use runOnJS to call JS functions like console.log runOnJS(console.log)("Updated scroll Y:", scrollY.value); }, }); return ( <Animated.ScrollView scrollEventThrottle={16} showsVerticalScrollIndicator={false} onScroll={scrollHandler} useNativeDriver={true} > {/* Your scrollable content goes here */} </Animated.ScrollView> ); }
Why Your Initial Attempts Failed
- Accessing
this.state.y._value: This is a private internal property ofAnimated.Value—React Native doesn't guarantee it will update whenuseNativeDriver: true(since animations run on the native thread, not the JS thread). Always use the value passed to the listener callback instead. - Misusing
addListener: You stored the value inthis._valuebut tried to printthis.state.y._valueinstead. Also, you didn't clean up the listener, which could cause memory leaks.
内容的提问来源于stack exchange,提问作者arp

