0

Mon code source complet de ce problème est affiché comme une application de l'Expo: https://exp.host/@kevinoldlifeway/swipe-scrollview-of-webviews ainsi que sur Github https://github.com/kevinold/swipe-scrollview-of-webviewsélément central « Sticky » de horizontal React ListView natif

Je construis une vue livre dans React autochtone. En utilisant un ScrollView, je voudrais glisser à gauche et à droite pour naviguer à travers les pages d'un titre qui pourrait avoir plusieurs centaines à plusieurs milliers. Puisque c'est le cas, mon but est de ne faire que la quantité minimale de données afin que l'utilisateur puisse glisser entre les pages, en voyant les pages immédiatement précédentes et suivantes.

Je suis en train de charger un tableau 3 élément comme ceci:

[Previous, Current, Next] 

qui serait mis à jour dans l'état par Redux (pas utilisé ici pour garder simples) et serait réengendrer et recentrer la liste.

Mon but est que mon ScrollView soit toujours "centré" sur la page "Current".

Les pages défilées à la page précédente et suivante sont traitées par une méthode handleScroll qui charge le tableau précalculé approprié afin que la page en cours reste active, mais les pages précédentes et suivantes (hors écran) sont mises à jour de manière appropriée.

handleScroll (event) { 
    //const x = event.nativeEvent.contentOffset.x; 

    const { activeIndex, scrollTimes } = this.state; 

    const windowWidth = Dimensions.get('window').width; 
    const eventWidth = event.nativeEvent.contentSize.width; 
    const offset = event.nativeEvent.contentOffset.x; 
    console.log('event width: ', eventWidth); 
    console.log('event offset: ', offset); 

    console.log('scrollTimes: ', scrollTimes); 
    //if (scrollTimes <= 1) return; 

    if (windowWidth + offset >= eventWidth) { 
     //ScrollEnd, do sth... 
     console.log('scrollEnd right (nextPage)', offset); 
     const nextIndex = activeIndex + 1; 
     console.log('nextIndex: ', nextIndex); 

    // Load next page 
    this.loadMore() 

    } else if (windowWidth - offset <= eventWidth) { 
     //ScrollEnd, do sth... 
     console.log('scrollEnd left (prevPage)', offset); 

    // Load prev page 
    this.loadPrev() 
    } 

    this.setState({ scrollTimes: scrollTimes + 1 }); 
} 

J'ai essayé d'équilibrer la page "actuelle" en utilisant une combinaison de:

contentOffset={{ x: width, y: 0 }} sur ScrollView

Et

componentDidMount() { 
    // Attempt to keep "center" element in array as focused "screen" in the horizontal list view 
    this.scrollView.scrollTo({ x: width, y: 0, animated: false }); 
} 

J'ai aussi essayé de scrollTo dans le rappel après this.setState, mais n'ont pas eu de chance.

Je me demande si ce "centrage" pourrait être accompli en utilisant Animated.

Répondre

1

J'ai donné un coup de feu mais je ne suis pas entièrement sûr d'avoir compris le problème, et je ne suis pas sûr à quel point cela résiste.

Fondamentalement, je viens de simplifier la fonction handleScroll de manière significative. D'abord vérifier si nous étions sur une fin de défilement et si c'est le cas si nous déterminons si nous avons atterri sur cet écran c'était l'écran "précédent" ou "suivant" - ne faites rien si c'est déjà l'écran du milieu.

Je pense que dans votre code, le problème était qu'il déclencherait et chargerait des données si c'était l'écran du milieu, pas seulement le premier ou le dernier. Par conséquent, il tirerait deux fois pour chaque transition.

Voici le handleScroll que je pense que travaillera pour vous.

handleScroll (event) { 
    const offset = event.nativeEvent.contentOffset.x; 
    const mod = offset % width; 

    if (mod === 0) { // only transition on scroll complete 
    if (offset === width * 2) { // last screen 
     console.log('load more') 
     this.loadMore(); 
     this.scrollView.scrollTo({ x: width, y: 0, animated: false }); 
    } else if (offset !== width) { // first screen 
     console.log('load prev') 
     this.loadPrev(); 
     this.scrollView.scrollTo({ x: width, y: 0, animated: false }); 
    } 
    } 
} 

et un Snack en le faisant défiler.