Para um aplicativo semelhante a um bate-papo, quero manter um ScrollView
componente rolado para a parte inferior, porque as mensagens mais recentes aparecem abaixo das mais antigas. Podemos ajustar a posição de rolagem de a ScrollView
?
Para um aplicativo semelhante a um bate-papo, quero manter um ScrollView
componente rolado para a parte inferior, porque as mensagens mais recentes aparecem abaixo das mais antigas. Podemos ajustar a posição de rolagem de a ScrollView
?
Respostas:
Para React Native 0.41 e posterior , você pode fazer isso com o scrollToEnd
método integrado :
<ScrollView
ref={ref => {this.scrollView = ref}}
onContentSizeChange={() => this.scrollView.scrollToEnd({animated: true})}>
</ScrollView>
root
caso contrário, scrollToEnd é indefinido. iethis.scrollView.root.scrollToEnd
root
realmente gera um erro indefinido.
ref={ref => {this.scrollView = ref}}
como você não deseja devolver a tarefa
Use onContentSizeChange para controlar o Y inferior da visualização de rolagem (altura)
https://facebook.github.io/react-native/docs/scrollview.html#oncontentsizechange
var _scrollToBottomY
<ScrollView
onContentSizeChange={(contentWidth, contentHeight)=>{
_scrollToBottomY = contentHeight;
}}>
</ScrollView>
em seguida, use o nome ref da visualização de rolagem, como
this.refs.scrollView.scrollTo(_scrollToBottomY);
Aqui está a solução mais simples que poderia reunir:
<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
});
}}
/>;
Para qualquer um que escreva um componente de função que possa usar o gancho,
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 })}
/>
);
};
tente esta solução
xcode 10.0
RN: 56.0.0
<ScrollView ref="scrollView"
onContentSizeChange={(width,height) => this.refs.scrollView.scrollTo({y:height})}> </ScrollView> // OR height - width
ref=
? parece uma relíquia de desenvolvimento da web
No caso de alguém em 2020 ou mais tarde estar se perguntando como conseguir isso com componentes funcionais. É assim que eu fiz:
ref={ref => scrollView = ref }
onContentSizeChange={() => scrollView.scrollToEnd({ animated: true })}>
Você pode inverter a visualização de rolagem / lista usando o react-native-invertible-scroll-view
módulo e , em seguida, basta chamar ref.scrollTo(0)
para rolar para baixo.
Instale o módulo:
npm install --save react-native-invertible-scroll-view
Em seguida, importe o componente:
import InvertibleScrollView from 'react-native-invertible-scroll-view';
Em seguida, use o seguinte JSX em vez de ScrollView
:
<InvertibleScrollView inverted
ref={ref => { this.scrollView = ref; }}
onContentSizeChange={() => {
this.scrollView.scrollTo({y: 0, animated: true});
}}
>
{ /* content */ }
</InvertibleScrollView>
Isso funciona porque react-native-invertible-scroll-view
inverte todo o conteúdo da visualização. Observe que os filhos da visualização também serão renderizados na ordem oposta a de uma visualização normal - o primeiro filho aparecerá na parte inferior .
Na verdade, a resposta @Aniruddha não funcionou para mim porque estou usando "react-native": "0.59.8"
e this.scrollView.root.scrollToEnd
também é indefinida
mas eu descobri e isso funciona this.scrollView.scrollResponderScrollToEnd({animated: true});
Se você estiver usando, 0.59.8
isso funcionará OU se estiver usando uma versão posterior e isso funcionar para você. adicione versões nesta resposta para que outras pessoas não tenham problemas.
Código completo aqui
<ScrollView
ref={ref => this.scrollView = ref}
onContentSizeChange={(contentWidth, contentHeight)=>{
this.scrollView.scrollResponderScrollToEnd({animated: true});
}}>
</ScrollView>
Este método é um pouco hacky, mas não consegui encontrar uma maneira melhor
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>
);
}
scrollToBottom
torna abordagens como essa obsoletas nas versões mais recentes do React Native.
Isso responde à sua pergunta: https://stackoverflow.com/a/39563100/1917250
Você precisa rolar constantemente para a parte inferior da página, calculando a altura do conteúdo menos a altura de seu scrollView.
Se você usa TypeScript, você precisa fazer isso
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>
Lutei com isso por um tempo e finalmente descobri algo que funcionou muito bem e suave para mim. Como muitos, tentei .scrollToEnd
sem sucesso. A solução que funcionou para mim foi uma combinação de onContentSizeChange
,onLayout
adereços e um pouco mais a pensar visualmente sobre "o que rolar para o fundo" realmente significava. A última parte parece trivial para mim agora, mas levei uma eternidade para descobrir.
Dado que o ScrollView
tem uma altura fixa, quando a altura do conteúdo ultrapassa a altura do contêiner, calculei o deslocamento subtraindo a prevHeight
(altura fixa de ScrollView
) de currHeight
(a altura do conteúdo). Se você puder imaginá-lo visualmente, rolar para essa diferença no eixo y desliza a altura do conteúdo sobre seu contêiner por esse deslocamento. Aumentei meu deslocamento e tornei minha altura de conteúdo atual minha altura anterior e continuei calculando um novo deslocamento.
Aqui está o código. Espero que ajude alguém.
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>
);
}
}
Acho que é tarde demais para responder, mas consegui um hack! Se você usar FlatList
você pode ativar inverted
a propriedade que cai de volta para definir transform scale
a -1
(o que é aceitável para outros componentes lista como ScrollView
...). Quando você renderiza seus FlatList
dados, ele sempre estará no fundo!
Tente definir a propriedade contentOffset da visualização de rolagem para a altura atual do conteúdo.
Para realizar o que você precisa, você pode fazer isso como parte do evento onScroll. No entanto, isso pode causar uma experiência ruim para o usuário, por isso pode ser mais amigável fazer isso apenas quando uma nova mensagem for anexada.
ScrollView
baixo para baixo todo o seu conteúdo, em vez de apenas rolar para o final.
Tive um problema parecido, mas depois de ler esta página (o que me dá dor de cabeça!) Achei esse pacote npm muito legal que inverte o ListView e facilita tudo para um aplicativo de chat !!
ScrollView
, não `ListView`).
Um pouco tarde ... mas olhe para esta questão. Role para cima de ScrollView
ScrollView tem um método "scrollTo".