如何在 React Native 中从上到下移动 ScrollView?

How to go from top to bottom of a ScrollView in React Native?

我在一个 React Native 项目中,客户希望产品图像在模式中从上到下滚动,反之亦然,我该如何实现?

我已经知道怎么解决了...

我必须创建一个计数器,每 0.5 秒增加或减少 ScrollView 的 Y 轴,并检查是否到达顶部或底部。

模态组件文件中:

import React, { useState, useEffect } from 'react';
import { StyleSheet, Modal, ScrollView, View, Image, NativeSyntheticEvent, NativeScrollEvent } from 'react-native';

import { Feather } from '@expo/vector-icons';

const ImageModal: React.FC<{ product: ProductType }> = ({ product }) => {

    const [ axisY, setAxisY ] = useState<number>(0); // State that is used to know the current Y axis of ScrollView 
    const [ scrollToTop, setScrollToTop ] = useState<boolean>(false); // State that is used to checks if should go to top or bottom

    // Handler that checks if ScrollView is scrolling to top or bottom
    const handleScroll = (event: NativeSyntheticEvent<NativeScrollEvent>) => {

        // HELP: https://newbedev.com/detect-scrollview-has-reached-the-end

        const { layoutMeasurement, contentOffset, contentSize } = event.nativeEvent; // Get scroll event properties

        // If scrolling to top
        if (scrollToTop) {
            const isNearTop = contentOffset.y != 0; // Checks if Y axis reached the top of ScrollView
            setScrollToTop(isNearTop); // Change the state value to FALSE, making ScrollView goes to bottom
        } else {
            const isNearBottom = layoutMeasurement.height + contentOffset.y >= contentSize.height; // Checks if Y axis reached the bottom of ScrollView
            setScrollToTop(isNearBottom); // Change the state value to TRUE, making ScrollView goes to top
        }

    }

    // Increase or decrease current Y axis every 0.5 seconds
    useEffect(() => {
        const timer = setInterval(() => {
            setAxisY(prev => !scrollToTop ? prev + 1.5 : prev - 1.5);
        }, 50);

        return () => clearInterval(timer);
    }, [scrollToTop]);

    return (
        <Modal
            visible={ true }
            transparent={ true }
            statusBarTranslucent={ true }
            animationType="fade"
        >
            <View style={ styles.container }>
                <View style={ styles.box }>
                    <ScrollView 
                        overScrollMode="never" 
                        style={ styles.scroll }
                        scrollEnabled={ false }
                        showsVerticalScrollIndicator={ false }
                        contentOffset={{ x: 0, y: axisY }}
                        onScroll={ handleScroll }
                    >
                        <View style={ styles.imageBox }>
                            <Image source={{ uri: product.image_url }} style={ styles.image } />
                        </View>
                    </ScrollView>

                    <View>
                        <Text>Some random text!</Text>
                    </View>
                </View>

                <TouchableOpacity style={ styles.closeButton } onPress={ onClose }>
                    <Feather name="x" size={ 30 } color="#fff" />
                </TouchableOpacity>
            </View>
        </Modal>
    );

}

// Main Styles
const styles = StyleSheet.create({
    container: {
        flex: 1,
        flexDirection: 'row',
        backgroundColor: 'rgba(0, 0, 0, 0.5)',
        padding: 20
    },
    closeButton: {
        width: 60,
        height: 60,
        borderWidth: 2,
        borderRadius: 12,
        marginLeft: 20,
        borderColor: '#fff',
        alignItems: 'center',
        justifyContent: 'center',
        backgroundColor: '#58585a'
    },
    box: {
        backgroundColor: '#fff',
        width: '80%',
        borderRadius: 10,
        flexDirection: 'column'
    },
    scroll: {
        width: '100%',
        height: '80%',
        borderBottomWidth: 1,
        borderColor: '#58585a'
    },
    imageBox: {
        width: '100%',
        height: 600,
    },
    image: {
        width: '100%',
        height: '100%',
        resizeMode: 'cover',
        borderTopLeftRadius: 10,
        borderTopRightRadius: 10
    }
});

export default ImageModal;