You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

React Native Animated.ScrollView调用scrollTo安卓无法水平滚动

问题描述

使用Animated.ScrollView实现多页滚动功能时,iOS端运行完全正常,但Android端调用scrollTo()方法会出现滚动卡住、无法水平滑动的问题。

CustomPagerView组件代码如下:

import { StyleSheet, Animated, Dimensions, Platform} from 'react-native';

const {width, height} = Dimensions.get('screen');

export const CustomPagerView = ({
  scrollViewRef,
  pageNumber,
  scrollX,
  setCurrentIndex,
  children,
  updateCurrentIndex,
}) => {
  return (
    <Animated.ScrollView
      ref={scrollViewRef}
      bounces={false}
      hozinontal={true}
      style={{flex: 1}}
      contentContainerStyle={{
        width: width * pageNumber,
        flexDirection: 'row',
        flexGrow: 1,
      }}
      disableIntervalMomentum={false}
      decelerationRate={'normal'}
      showPageIndicator={false}
      pagingEnabled
      onMomentumScrollEnd={updateCurrentIndex}
      onScroll={Animated.event([{nativeEvent: {contentOffset: {x: scrollX}}}], {
        useNativeDriver: false,
      })}
      showsHorizontalScrollIndicator={false}
      scrollEnabled={false}
      onScrollEndDrag={() => {
        console.log('scrollViewRef.current>>>', scrollViewRef.current);
        setCurrentIndex(scrollViewRef.current);
      }}
      scrollEventThrottle={400}>
      {children}
    </Animated.ScrollView>
  );
};

const styles = StyleSheet.create({
  container: {
    width,
    height,
    justifyContent: 'center',
    alignItems: 'center',
    paddingBottom: Platform.OS === 'android' ? 40 : 0,
  },
});

组件调用方式如下:

<CustomPagerView
  scrollViewRef={scrollViewRef}
  pageNumber={3}
  scrollX={scrollX}
  setCurrentIndex={setCurrentIndex}
  updateCurrentIndex={updateCurrentIndex}>
  <View key="0" style={{width, flex: 1}}>
    <Component1 />
  </View>
  <View key="1" style={{width, flex: 1}}>
    <Component2 key="1" navigation={navigation} />
  </View>
  <View key="2" style={{width, flex: 1}}>
    <Component3 navigation={navigation} />
  </View>
</CustomPagerView>

父组件中定义的相关状态和逻辑代码:

const scrollX = useRef(new Animated.Value(0)).current;
const scrollViewRef = useRef();
const [currentIndex, setCurrentIndex] = useState(0);

const {setTitle} = useContext(ReportTitleContext);
const [currentPageNumber, setCurrentPageNumber] = useState(0);

let pagerViewRef = useRef();

const updateCurrentIndex = (e) => {
  const contentOffsetX = Number(e.nativeEvent.contentOffset.x);
  const updatedCurrentIndex = Math.round(contentOffsetX / width);
  setCurrentIndex(updatedCurrentIndex);
};
const onNextPageHandler = () => {
  setCurrentIndex(currentIndex + 1);
  setTitle(headerText[currentIndex + 1]);
  // scrollX.setValue((currentIndex + 1) * width);
  scrollViewRef.current.scrollTo({
    x: (currentIndex + 1) * width,
    y: 0,
    animated: true,
  });
};

const onPreviousPageHandler = () => {
  setCurrentIndex(currentIndex - 1);
  setTitle(headerText[currentIndex - 1]);
  scrollViewRef.current.scrollTo({
    x: (currentIndex - 1) * width,
    y: 0,
    animated: true,
  });
};
修复方案

代码中有3个直接导致Android端滚动异常的问题,按顺序修改即可:

  • 属性拼写错误:Animated.ScrollView的水平滚动属性是horizontal,代码中错写为hozinontal。iOS对属性拼写容错更高,但Android端识别不到该属性时会默认按垂直滚动处理,调用水平方向的scrollTo自然会卡住。
  • 回调逻辑错误:onScrollEndDrag回调中错误地将scrollViewRef.current(ScrollView组件实例对象)传给了setCurrentIndex,每次拖拽结束都会把原本存储页码的currentIndex状态覆盖为对象,后续计算滚动位置时(currentIndex + 1) * width会得到NaN,直接导致滚动位置异常。这段逻辑可以直接删除,页码更新已经在onMomentumScrollEnd绑定的updateCurrentIndex中完成。
  • Android兼容配置问题:把scrollEventThrottle的值从400改成16,匹配60fps的屏幕刷新频率;将onScroll动画的useNativeDriver设为true,避免JS线程拥堵导致动画卡顿;去掉contentContainerStyle中的flexGrow: 1,Android下该属性会导致水平滚动容器高度计算异常;翻页方法中增加空值判断和边界判断,避免组件未挂载或页码越界时调用方法报错。

修改后的核心代码参考:

// Animated.ScrollView属性修正
<Animated.ScrollView
  ref={scrollViewRef}
  bounces={false}
  horizontal={true}
  style={{flex: 1}}
  contentContainerStyle={{
    width: width * pageNumber,
    flexDirection: 'row',
  }}
  disableIntervalMomentum={false}
  decelerationRate={'normal'}
  pagingEnabled
  onMomentumScrollEnd={updateCurrentIndex}
  onScroll={Animated.event([{nativeEvent: {contentOffset: {x: scrollX}}}], {
    useNativeDriver: true,
  })}
  showsHorizontalScrollIndicator={false}
  scrollEnabled={false}
  scrollEventThrottle={16}>
  {children}
</Animated.ScrollView>
// 翻页方法修正
const onNextPageHandler = () => {
  if (!scrollViewRef.current || currentIndex >= 2) return;
  const nextIndex = currentIndex + 1;
  setCurrentIndex(nextIndex);
  setTitle(headerText[nextIndex]);
  scrollViewRef.current.scrollTo({
    x: nextIndex * width,
    y: 0,
    animated: true,
  });
};

const onPreviousPageHandler = () => {
  if (!scrollViewRef.current || currentIndex <= 0) return;
  const prevIndex = currentIndex - 1;
  setCurrentIndex(prevIndex);
  setTitle(headerText[prevIndex]);
  scrollViewRef.current.scrollTo({
    x: prevIndex * width,
    y: 0,
    animated: true,
  });
};

内容的提问来源于stack exchange,提问作者jalaliyev

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.27 05:24:28