是否可以将 ScrollView 滚动到底部?

对于一个类似聊天的应用程序,我希望保持 ScrollView组件滚动到底部,因为最新的消息出现在旧的消息下面。我们可以调整 ScrollView的滚动位置吗?

131576 次浏览

尝试将滚动视图的 ContentOffset属性设置为内容的当前高度。

要完成您需要的任务,您可以将其作为 onScroll 事件的一部分。然而,这可能会导致糟糕的用户体验,因此只有在添加新消息时才这样做可能会更加方便用户。

有点晚了... 但是看看这个问题

ScrollView 有一个“ scrollTo”方法。

您可以使用 react-native-invertible-scroll-view模块反转滚动/列表视图,然后简单地调用 ref.scrollTo(0)来滚动到底部。

安装模块:

npm install --save react-native-invertible-scroll-view

然后导入组件:

import InvertibleScrollView from 'react-native-invertible-scroll-view';

然后使用以下 JSX 代替 ScrollView:

<InvertibleScrollView inverted
ref={ref => { this.scrollView = ref; }}
onContentSizeChange={() => {
this.scrollView.scrollTo({y: 0, animated: true});
}}
>
{ /* content */ }
</InvertibleScrollView>

这是因为 react-native-invertible-scroll-view翻转了整个视图的内容。请注意,视图的子视图也将以与正常视图相反的顺序呈现-第一个子视图将出现在 底部

这个方法有一点古怪,但我找不到更好的方法

  1. 首先向 ScrollView 添加一个引用。
  2. 然后在关闭 ScrollView 标记之前添加一个虚拟 View
  3. 得到那个虚拟视图的 y 位置
  4. 每当你想滚动到底部滚动到虚拟视图的位置

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>
);
}

使用 onContentSizeChange 跟踪滚动视图的底部 Y (高度)

Https://facebook.github.io/react-native/docs/scrollview.html#oncontentsizechange

var _scrollToBottomY


<ScrollView
onContentSizeChange={(contentWidth, contentHeight)=>{
_scrollToBottomY = contentHeight;
}}>
</ScrollView>

然后使用滚动视图的参考名称,如

this.refs.scrollView.scrollTo(_scrollToBottomY);

这是我能想到的最简单的解决办法:

 <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
});
}}
/>;

这就回答了你的问题: Https://stackoverflow.com/a/39563100/1917250

通过计算内容的高度减去 scrollView 的高度,您需要不断地滚动到页面的底部。

对于 本机反应0.41及以后,您可以使用内置的 scrollToEnd方法来完成:

<ScrollView
ref={ref => {this.scrollView = ref}}
onContentSizeChange={() => this.scrollView.scrollToEnd({animated: true})}>
</ScrollView>

我也有过类似的问题,但是在读了这一页之后(这让我很头疼!)我发现 这个非常好的 npm 软件包只是反转列表视图,使一切很容易为一个聊天应用程序! !

试试这个办法

代码10.0

RN: 56.0.0

<ScrollView ref="scrollView"
onContentSizeChange={(width,height) => this.refs.scrollView.scrollTo({y:height})}>  </ScrollView> // OR height -  width

我花了很长时间,终于想出了一个对我来说非常顺利的方法。像许多人一样,我尝试了 .scrollToEnd,但没有用。对我有效的解决方案是结合了 onContentSizeChangeonLayout道具和一点点更多的视觉思考“什么滚动到底部”真正意味着。最后一部分对我来说微不足道,但我花了很长时间才弄明白。

假设 ScrollView有一个固定的高度,当内容高度超过容器的高度时,我通过减去 prevHeight(ScrollView的固定高度)来计算 currHeight(内容高度)的偏移量。如果可以直观地想象,滚动到 y 轴的差值,就可以通过该偏移量将内容高度滑动到其容器上。我增加了我的偏移量,使现在的内容高度成为以前的高度,并不断计算新的偏移量。

这是密码,希望对谁有帮助。

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>
);
}
}

我想现在回答已经太晚了,但是我还有一个问题!如果您使用 FlatList,您可以启用 inverted属性,该属性退回到将 transform scale设置为 -1(这对于其他列表组件(如 ScrollView...)是可以接受的)。当你使用数据渲染你的 FlatList时,它总是在底部!

事实上@Aniruddha 的回答对我来说不起作用,因为我使用的是 "react-native": "0.59.8",而且 this.scrollView.root.scrollToEnd也是未定义的

但我弄明白了,这个能用 this.scrollView.scrollResponderScrollToEnd({animated: true});

如果你使用 0.59.8这将工作或如果你使用后来的版本,这为你工作。请在这个答案中添加版本,这样其他人就不会遇到麻烦。

完整密码

<ScrollView
ref={ref => this.scrollView = ref}
onContentSizeChange={(contentWidth, contentHeight)=>{
this.scrollView.scrollResponderScrollToEnd({animated: true});
}}>
</ScrollView>

如果使用 TypeScript,则需要执行此操作

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>

如果2020年或更晚些时候有人想知道如何用功能性组件实现这一点。我是这样做的:

ref={ref => scrollView = ref }
onContentSizeChange={() => scrollView.scrollToEnd({ animated: true })}>

对于任何编写可以使用 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 })}
/>
);
};

你可以这样做:

首先初始化 ref 对象:

const scrollViewRef = React.useRef<ScrollView>();

然后像下面这样使用它:

<ScrollView
ref={scrollViewRef}
nestedScrollEnabled={true}
onContentSizeChange={(contentWidth, contentHeight) => {
scrollViewRef.current?.scrollTo({ y: contentHeight });
}}
>
{children}
</ScrollView>

对于那些在使用 scrollToEndonContentSizeChange道具时有 bug (有时它会滚动到列表的顶部,而不是底部,并且随机发生)的人,下面是我使用的替代方案。

   onContentSizeChange={(_, contentHeight) => {
flatListRef.current?.scrollToOffset({ offset: contentHeight });
}}