Flutter sends a message by itself, the list jumps to the bottom, and when the message is received, if it is not at the bottom, it will display "There are unread messages", click to jump to the bottom

First judge whether the message is sent by yourself. If it is sent by yourself, the list will jump to the bottom. If it is not a message sent by yourself, judge whether it is at the bottom. If it is not at the bottom, it will display "There are unread messages". If it is at the bottom There is no need to display "There are unread messages". Tap "Have unread messages" to jump to the bottom of the list. Because the list is reversed, the bottom is 0. top is the list height

  late StreamSubscription<ReceiveNewMessageEvent> _receiveNewMessageEvent;
  final ScrollController _scrollController = ScrollController();

  //插入一条新消息,判断是否时自己的消息
  handleMessage(int userId) {
    
    
    if ('$userId' == Global.userId) {
    
    
      //是自己发的消息
      EventBusUtil.fire(ReceiveNewMessageEvent(CloudCustomDataBean.LIVE_MESSAGE, true));
    } else {
    
    
      //不是自己发的消息
      EventBusUtil.fire(ReceiveNewMessageEvent(CloudCustomDataBean.LIVE_MESSAGE, false));
    }
  }

    ///新消息处理
    _receiveNewMessageEvent = EventBusUtil.listen((event) {
    
    
      if (event.messageType == CloudCustomDataBean.LIVE_MESSAGE) {
    
    
        if (event.isOneself) {
    
    
          //是自己的消息,弹到底部
          _scrollController.animateTo(
              _scrollController.position.minScrollExtent, //滚动到底部
              duration: const Duration(milliseconds: 200),
              curve: Curves.easeOut);
        } else {
    
    
          //不是自己的消息,不在列表底部就判断是否显示未读消息控件
          if (!isOnTheBottom) {
    
    
            //显示有未读消息控件
            isNewMessage = true;
            mySetState(() {
    
    });
          }
        }
      }
    });


    /// 监听滚动事件,判断列表是否到达底部
    _scrollController.addListener(() {
    
    
      if (_scrollController.position.pixels <=
          _scrollController.position.minScrollExtent + 30) {
    
    
        //小于距离底部30位置的算滑到底部了
        ///达到最大指定滚动位置
        isOnTheBottom = true;
        isNewMessage = false;
      } else {
    
    
        //因为列表反转了,底下是0,顶部是列表最大高度,所以列表滑动超过距离底部30的位置时就会设置还没到列表底部(大概滑到距离底部两条消息的距离才会显示还有未读消息)
        isOnTheBottom = false;
      }
      mySetState(() {
    
    });
    });

  @override
  void dispose() {
    
    
  _receiveNewMessageEvent.cancel();
  _scrollController.dispose();
  super.dispose();
  }
//列表数据
            DirectSeedingList(
                                  widget.roomId ?? '0',
                                  liveGroupInfo,
                                  _scrollController,
                                  widget.anchorInfo),

//点击未读消息按钮跳到底部
      Offstage(
          offstage: !isNewMessage,
          child: GestureDetector(
              onTap: () {
    
    
                _scrollController.animateTo(
                    _scrollController.position.minScrollExtent, //滚动到底部
                    duration: const Duration(milliseconds: 200),
                    curve: Curves.easeOut);
              },
              child: Container(
                  margin: const EdgeInsets.only(bottom: 8,left: 15),
                  padding: const EdgeInsets.fromLTRB(11, 8, 11, 8),
                  decoration: BoxDecorationUtil()
                      .setFillBoxDecoration(Colors.white, 15.0),
                  child: Row(
                      crossAxisAlignment: CrossAxisAlignment.center,
                      mainAxisSize: MainAxisSize.min,
                      children: [
                        ContentText(S.current.group_unread, 12.0,
                            const Color(0xFFE95D47),
                            fontWeight: FontWeight.w500),
                        RightPadding(4),
                        const Image(
                            image: AssetImage(
                                'assets/images/group/icon_group_new_message.png'),
                            width: 9,
                            height: 9,
                            gaplessPlayback: true,color: Color(0xFFE95D47),)
                      ]))))

list layout

import 'dart:async';

import 'package:audioplayers/audioplayers.dart';
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
import 'package:social_im/common/globalEventBus.dart';
import 'package:social_im/models/cloudCustomDataBean.dart';
import 'package:social_im/models/group/groupInfoBean.dart';
import 'package:social_im/utils/loadingUtil.dart';
import 'package:social_im/utils/widgetAdaptation.dart';
import '../../../provider/direct_seeding_message_list_model.dart';
import '../direct_model/direct_anchor_info.dart';
import '../direct_seeding_message_model/direct_seeding_all_message_model.dart';
import 'direct_message_item.dart';

class DirectSeedingList extends StatefulWidget {
    
    
  String groupId;
  GroupInfoBean? liveGroupInfo;
  ScrollController scrollController;
  DirectAnchorInfoEnter? anchorInfo;

  DirectSeedingList(
      this.groupId, this.liveGroupInfo, this.scrollController, this.anchorInfo);

  @override
  State<StatefulWidget> createState() => DirectSeedingListState();
}

class DirectSeedingListState extends State<DirectSeedingList> {
    
    
  /// 滚动控制器
  final GlobalKey _containerKey = GlobalKey();
  List<DirectSeedingAllMessageModel> groupMessageList = [];
  double clmHeight = 0;
  AudioPlayer audioPlayer = AudioPlayer();

  late StreamSubscription<GetSelfRole>? _getSelfRole;

  int userRole = 0;

  @override
  void initState() {
    
    
    super.initState();
    _getSelfRole = EventBusUtil.listen((event) {
    
    
      userRole = event.userRole;
      mySetState(() {
    
    });
    });
    // receiveMessage();
    WidgetsBinding.instance!.addPostFrameCallback(_afterLayout);
  }

  @override
  void dispose() {
    
    
    if (_getSelfRole != null) {
    
    
      _getSelfRole!.cancel();
    }
    LoadingUtil.dismissLoading();
    // removeMessage();
    super.dispose();
  }

  _afterLayout(_) {
    
    
    Future.delayed(const Duration(milliseconds: 100), () {
    
    
      if (mounted) {
    
    
        setState(() {
    
    
          clmHeight = _containerKey.currentContext!.size!.height;
        });
      }
    });
  }

  mySetState(callBack) {
    
    
    if (mounted) {
    
    
      setState(() {
    
    
        callBack();
      });
    }
  }

  @override
  Widget build(BuildContext context) {
    
    
    groupMessageList =
        Provider.of<DirectSeedingMessageListModel>(context, listen: true)
            .directSeedingMessageList;

    return ShaderMask(
        //此处是背景透明度渐变的处理
        shaderCallback: (Rect bounds) {
    
    
          return const LinearGradient(
            begin: Alignment.topCenter,
            end: Alignment.bottomCenter,
            colors: [
              Color.fromRGBO(0, 0, 0, 0),
              Color.fromRGBO(0, 0, 0, 1),
              Color.fromRGBO(0, 0, 0, 1),
              Color.fromRGBO(0, 0, 0, 1),
              Color.fromRGBO(0, 0, 0, 1),
              Color.fromRGBO(0, 0, 0, 1),
              Color.fromRGBO(0, 0, 0, 1),
              Color.fromRGBO(0, 0, 0, 1),
            ],
          ).createShader(Rect.fromLTRB(0, 0, bounds.width, bounds.height));
        },
        blendMode: BlendMode.dstIn,
        child: SingleChildScrollView(
            controller: widget.scrollController,
            scrollDirection: Axis.vertical,
            key: _containerKey,

            ///注意设置为反向,
            reverse: groupMessageList.length >= 2 ? true : false,
            child: Column(children: [
              MediaQuery.removePadding(
                  removeTop: true,
                  context: context,
                  child: ListView.builder(
                      shrinkWrap: true,
                      physics: const NeverScrollableScrollPhysics(),
                      itemCount: groupMessageList.length,
                      itemBuilder: (BuildContext context, int index) {
    
    
                        return showItemView(groupMessageList[index]);
                      }))
            ])));
  }

  Widget showItemView(DirectSeedingAllMessageModel groupMessage) {
    
    
    Widget groupMessageView = Container();
    groupMessageView = Container(
      margin: EdgeInsets.only(
          left: WidgetAdaptation.getWidth(15),
          right: WidgetAdaptation.getWidth(15)),
      child: DirectMessageItem(
        groupMessage,
        audioPlayer,
        activityType: CloudCustomDataBean.WORLD_LIVE_GROUP,
        roomId: int.parse(widget.groupId),
        anchorInfo: widget.anchorInfo,
        userRole: userRole,
      ),
    );
    return groupMessageView;
  }
}

Guess you like

Origin blog.csdn.net/weixin_44911775/article/details/130237932