I\'m building a chat application and I\'ve reached the part where I\'m creating the actual chat interface. I decided to use the ListView.builder()
constructor, as I\'m working with potentially a great amount of data (messages). The layout, and my code in general, look something like this.
I want to preserve the scrolling position at any time, unless the user explicitly scrolls away. Here comes the first issue: when the software keyboard appears, or the size of the input field changes, I would like the bottom of the messages area to stay visible, and the older (ie. above) messages to get pushed out of the screen. You know, the way it works in Messenger, etc. However, it doesn\'t work like that. The older messages stay visible, and the newer ones get pushed put.
\nTo achieve this, I tried to set the reverse
argument to true
. While it indeed solved the above issues, it created a newer one. Whenever a new message is added (since it is "reversed", I have to prepend the messages list), the whole messages area appears to "jump". It is, I believe, due to the fact that the since ListView
is reversed, the item with index 0 is always the newest message.
However, I don\'t like this behavior. It doesn\'t seem intuitive to the user, who either expects to be scrolled down to the latest message, or be shown a floating UI element indicating that there are new messages.
\nQuestion #1: can I somehow disable/change the above behavior for reversed list? I\'m thinking of a callback that calculates the "old" offset and instantly scrolls to that location when a new message is added. Not sure if it\'s possible or if it fits the pattern.
\n问题#2:我想不使用反向列表,而是添加类似 a 的内容SizeChangedLayoutNotifier
,监听 的大小变化ListView
,然后滚动到相应的位置。不过,这看起来也很黑客。
一般来说,我想实现类似 Messenger(或者实际上是任何其他类似应用程序)的行为。打开软件键盘应该“上推”消息,并且当新消息到达时,不应该有任何跳转或自动滚动。
\n更新#1:找到了解决方法,但我宁愿不采用它。每当添加一个项目时,我都会获得position.maxScrollExtent
的值ScrollController
,然后在更新状态后,我会获得新值。用旧值减去新值,然后减去当前偏移量的差值,最后得到jumpTo
这个值。瞧\xc3\xa0, we are at the same message. This has multiple drawbacks, though:
由于上述原因,我决定不使用此解决方法。
\n谢谢。
\n小智 -1
您可以将默认的scrollPhysics更改为此类,以在添加新消息时保留当前位置。用户仍然可以滚动浏览他的消息。
我只是将代码放在这里,供仍在寻找解决方案的人使用。
class PositionRetainedScrollPhysics extends ScrollPhysics {
final bool? shouldRetain;
const PositionRetainedScrollPhysics({
super.parent,
this.shouldRetain = true,
});
@override
PositionRetainedScrollPhysics applyTo(ScrollPhysics? ancestor){
return PositionRetainedScrollPhysics(
parent: buildParent(ancestor),
shouldRetain: shouldRetain,
);
}
@override
double adjustPositionForNewDimensions({
required ScrollMetrics oldPosition,
required ScrollMetrics newPosition,
required bool isScrolling,
required double velocity,
}) {
final position = super.adjustPositionForNewDimensions(
oldPosition: oldPosition,
newPosition: newPosition,
isScrolling: isScrolling,
velocity: velocity,
);
// Check if the new position exceeds the scrollable extents
if (newPosition.maxScrollExtent < oldPosition.maxScrollExtent) {
return position.clamp(
oldPosition.minScrollExtent,
oldPosition.maxScrollExtent,
);
}
final diff = newPosition.maxScrollExtent - oldPosition.maxScrollExtent;
if (!isScrolling && shouldRetain) {
return position + diff;
} else {
return position;
}
}
}
Run Code Online (Sandbox Code Playgroud)
归档时间: |
|
查看次数: |
1469 次 |
最近记录: |