Per un'app simile a una chat, voglio che un ScrollViewcomponente scorra fino in fondo, perché i messaggi più recenti vengono visualizzati sotto quelli più vecchi. Possiamo regolare la posizione di scorrimento di a ScrollView?
Per un'app simile a una chat, voglio che un ScrollViewcomponente scorra fino in fondo, perché i messaggi più recenti vengono visualizzati sotto quelli più vecchi. Possiamo regolare la posizione di scorrimento di a ScrollView?
Risposte:
Per React Native 0.41 e versioni successive , puoi farlo con il scrollToEndmetodo integrato :
<ScrollView
ref={ref => {this.scrollView = ref}}
onContentSizeChange={() => this.scrollView.scrollToEnd({animated: true})}>
</ScrollView>
rootaltrimenti scrollToEnd non è definito. vale a direthis.scrollView.root.scrollToEnd
rootrealtà genera un errore indefinito.
ref={ref => {this.scrollView = ref}}poiché non desideri restituire il compito
Utilizzare onContentSizeChange per tenere traccia della Y inferiore della visualizzazione a scorrimento (altezza)
https://facebook.github.io/react-native/docs/scrollview.html#oncontentsizechange
var _scrollToBottomY
<ScrollView
onContentSizeChange={(contentWidth, contentHeight)=>{
_scrollToBottomY = contentHeight;
}}>
</ScrollView>
quindi utilizzare il nome di riferimento della visualizzazione a scorrimento come
this.refs.scrollView.scrollTo(_scrollToBottomY);
Ecco la soluzione più semplice che potrei trovare:
<ListView
ref={ref => (this.listView = ref)}
onLayout={event => {
this.listViewHeight = event.nativeEvent.layout.height;
}}
onContentSizeChange={() => {
this.listView.scrollTo({
y: this.listView.getMetrics().contentLength - this.listViewHeight
});
}}
/>;
Per chiunque scriva un componente funzione che può utilizzare hook,
import React, { useRef } from 'react';
import { ScrollView } from 'react-native';
const ScreenComponent = (props) => {
const scrollViewRef = useRef();
return (
<ScrollView
ref={scrollViewRef}
onContentSizeChange={() => scrollViewRef.current.scrollToEnd({ animated: true })}
/>
);
};
Nel caso in cui qualcuno nel 2020 o successivamente si chieda come ottenere questo risultato con componenti funzionali. Ecco come ho fatto:
ref={ref => scrollView = ref }
onContentSizeChange={() => scrollView.scrollToEnd({ animated: true })}>
prova questa soluzione
xcode 10.0
RN: 56.0.0
<ScrollView ref="scrollView"
onContentSizeChange={(width,height) => this.refs.scrollView.scrollTo({y:height})}> </ScrollView> // OR height - width
ref=? sembra una reliquia dello
È possibile invertire la visualizzazione a scorrimento / elenco utilizzando il react-native-invertible-scroll-viewmodulo , quindi chiamare semplicementeref.scrollTo(0) per scorrere fino in fondo.
Installa il modulo:
npm install --save react-native-invertible-scroll-view
Quindi importa il componente:
import InvertibleScrollView from 'react-native-invertible-scroll-view';
Quindi utilizza il seguente JSX invece di ScrollView:
<InvertibleScrollView inverted
ref={ref => { this.scrollView = ref; }}
onContentSizeChange={() => {
this.scrollView.scrollTo({y: 0, animated: true});
}}
>
{ /* content */ }
</InvertibleScrollView>
Funziona perché react-native-invertible-scroll-viewcapovolge il contenuto dell'intera visualizzazione. Nota che anche i figli della vista verranno renderizzati nell'ordine opposto a una vista normale: il primo figlio apparirà in basso .
In realtà la risposta di @Aniruddha non ha funzionato per me perché sto usando "react-native": "0.59.8"ed this.scrollView.root.scrollToEndè anche indefinita
ma l'ho capito e funziona this.scrollView.scrollResponderScrollToEnd({animated: true});
Se stai usando 0.59.8questo funzionerà OPPURE se stai usando una versione successiva e questo funziona per te. si prega di aggiungere versioni in questa risposta in modo che gli altri non abbiano problemi.
Codice completo qui
<ScrollView
ref={ref => this.scrollView = ref}
onContentSizeChange={(contentWidth, contentHeight)=>{
this.scrollView.scrollResponderScrollToEnd({animated: true});
}}>
</ScrollView>
Questo metodo è un po 'complicato ma non sono riuscito a trovare un modo migliore
var footerY; //Y position of the dummy view
render() {
return (
<View>
<ScrollView
ref='_scrollView'>
// This is where all the things that you want to display in the scroll view goes
// Below is the dummy View
<View onLayout={(e)=> {
footerY = e.nativeEvent.layout.y;
}}/>
</ScrollView>
//Below is the button to scroll to the bottom
<TouchableHighlight
onPress={() => { this.refs._scrollView.scrollTo(footerY); }}>
<Text>Scroll to Bottom</Text>
</TouchableHighlight>
</View>
);
}
scrollToBottomrende approcci come questo obsoleti nelle versioni più recenti di React Native.
Questo risponde alla tua domanda: https://stackoverflow.com/a/39563100/1917250
È necessario continuare a scorrere costantemente fino alla fine della pagina calcolando l'altezza del contenuto meno l'altezza del suo scrollView.
Se usi TypeScript, devi farlo
interface Props extends TextInputProps {
scrollRef?: any;
}
export class Input extends React.Component<Props, any> {
scrollRef;
constructor(props) {
this.scrollRef = React.createRef();
}
<ScrollView
ref={ref => (this.scrollRef = ref)}
onContentSizeChange={() => {
this.scrollRef.scrollToEnd();
}}
>
</ScrollView>
Ho combattuto con questo per un po 'e alla fine ho trovato qualcosa che funzionava davvero bene e senza intoppi per me. Come molti, ho provato .scrollToEndinutilmente. La soluzione che ha funzionato per me è stata una combinazione di onContentSizeChange,onLayout oggetti di scena e un po 'di più a pensare visivamente su "ciò che scorrendo verso il basso" in realtà significava. L'ultima parte ora mi sembra banale, ma mi ci è voluta un'eternità per capirla.
Dato che ScrollViewha un'altezza fissa, quando l'altezza del contenuto supera l'altezza del contenitore, ho calcolato l'offset sottraendo l ' prevHeight(altezza fissa del ScrollView) per ilcurrHeight (l'altezza del contenuto). Se puoi immaginarlo visivamente, scorrendo fino a quella differenza nell'asse y, fai scorrere l'altezza del contenuto sul suo contenitore di tale offset. Ho incrementato il mio offset e ho impostato l'altezza del contenuto attuale come quella precedente e ho continuato a calcolare un nuovo offset.
Ecco il codice. Spero che aiuti qualcuno.
class ChatRoomCorrespondence extends PureComponent {
currHeight = 0;
prevHeight = 0;
scrollHeight = 0;
scrollToBottom = () => {
this.refs.scrollView.getScrollResponder().scrollResponderScrollTo({
x: 0,
y: this.scrollHeight,
animated: true
});
};
render() {
return (
<ScrollView
style={Styles.container}
ref="scrollView"
onContentSizeChange={(w, h) => {
this.currHeight = h;
if (
this.prevHeight > 0 &&
this.currHeight - this.scrollHeight > this.prevHeight
) {
this.scrollHeight += this.currHeight - this.prevHeight;
console.log("--------------------------------------------");
console.log("Curr: ", this.currHeight);
console.log("Prev: ", this.prevHeight);
console.log("Scroll: ", this.scrollHeight);
this.prevHeight = this.currHeight;
console.log("PREV: ", this.prevHeight);
console.log("--------------------------------------------");
this.scrollToBottom();
}
}}
onLayout={ev => {
// Fires once
const fixedContentHeight = ev.nativeEvent.layout.height;
this.prevHeight = fixedContentHeight;
}}
>
<FlatList
data={this.props.messages}
renderItem={({ item }) => (
<ChatMessage
text={item.text}
sender={item.sender}
time={item.time}
username={this.props.username}
/>
)}
keyExtractor={(item, index) => index.toString()}
/>
</ScrollView>
);
}
}
Immagino sia troppo tardi per rispondere ma ho un trucco! Se si utilizza FlatListè possibile attivare la invertedproprietà che ricade impostazione transform scalea -1(che è accettabile per gli altri componenti della lista, come ScrollView...). Quando esegui il rendering FlatListcon i dati, sarà sempre in fondo!
Prova a impostare la proprietà contentOffset della visualizzazione a scorrimento sull'altezza corrente del contenuto.
Per realizzare ciò di cui hai bisogno potresti farlo come parte dell'evento onScroll. Tuttavia, ciò potrebbe creare una cattiva esperienza utente, quindi potrebbe rivelarsi più facile da usare farlo solo quando viene aggiunto un nuovo messaggio.
ScrollViewverso il basso fino al di sotto di tutto il suo contenuto, piuttosto che scorrere verso il basso.
Ho avuto un problema simile, ma dopo aver letto questa pagina (che mi fa venire il mal di testa!) Trovo questo simpaticissimo pacchetto npm che basta invertire ListView e rendere tutto più semplice per un'applicazione di chat !!
ScrollView, non `ListView`).
Un po 'tardi ... ma guarda questa domanda. Scorri fino all'inizio di ScrollView
ScrollView ha un metodo "scrollTo".