ScrollController 在 ListView.builder 完成时跳转到

ScrollController jumpto when ListView.builder complete

我正在用 flutter 创建一个与 firebase 的聊天,我希望当 listview 构建器完成时它可以转到列表的末尾(最后一条消息)。

这是我的构建方法的样子:

return Scaffold(
    backgroundColor: Color(0xFFf1e4e8),
    body: Stack(
      children: [
        Container(
          padding: EdgeInsets.only(bottom: 125),
          child: StreamBuilder(
              stream: userBloc.chat(widget.chatID),
              builder: (context, AsyncSnapshot<QuerySnapshot> snapshot) {                    
                if (!snapshot.hasData) {
                  return Center(
                    child: CircularProgressIndicator(),
                  );
                } else if(snapshot.connectionState == ConnectionState.done && snapshot.hasData) {                  
                  return ListView.builder(
                    controller: scrollController,
                    physics: BouncingScrollPhysics(),
                    itemCount: snapshot.data.size,
                    itemBuilder: (context, index) {
                      return ChatMessage(
                          isUserMessage: isUserMessage(snapshot,index),
                          message:
                              snapshot.data.docs[index].data()['Message'],
                              timeStamp:snapshot.data.docs[index].data()['Timestamp']);
                    },
                  );
                }
              }),
 );

正确的做法是什么?

在您的 initState() 中,您可以使用 addPostFrameCallback 注册一个回调,它会在第一帧完成渲染后被调用一次。您可以使用此回调滚动到 ListView 的底部。

@override
void initState() {
  super.initState();

  WidgetsBinding.instance.addPostFrameCallback( (_) {
     _scrollToBottomOfListView();
  }
}



  

最简单的解决方案如下:

StreamBuilder(
  stream: FirebaseFirestore.instance
  .collection('<MessagesColection>')
  .orderBy('<Time field>',descending: true)
  .snapshots(),
  builder: (context,snapshot) {                    
      return ListView.builder(
        //The reversed list will put the list backwards. 
        //The start of the list will start at the bottom.
        reverse: true, 
        controller: scrollController,      
        itemCount: snapshot.data.size,
        itemBuilder: (context, index) {                                                    
          return ChatMessage(snapshot);          
        },
      );
    }
),

在前面的代码中,所做的是将列表反转,最近的消息会在底部,并且按照降序排列记录,即从最近到最不最近。这样,最新的消息将位于列表的开头(在本例中位于底部),最少的位于列表底部(在本例中位于顶部)。

将 addListener 附加到您的滚动控制器,然后相应地使用 jumpTo 函数。你可以按照这个例子

ScrollController _scrollController;

double _lastEndOfScroll = 0;   

_scrollController.addListener(() {

double maxScroll = _scrollController.position.maxScrollExtent;
double currentScroll = _scrollController.position.pixels;
if (maxScroll == currentScroll) {

   _lastEndOfScroll = maxScroll;
 
}
 });

_scrollController.jumpTo(_lastEndOfScroll);