flutter left and right cycle marquee, html implementation

import 'dart:async';
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:flutter_html/flutter_html.dart';
import 'package:flutter_screenutil/flutter_screenutil.dart';
import '../../../common/Global.dart';
import '../../../common/globalEventBus.dart';
import '../../../models/group/groupUserBean.dart';
import '../../../svga/CoverScreen.dart';
import '../../../utils/printUtil.dart';
import '../../widget/marquee_view.dart';

class DirectSeedingNoticeDialog extends StatefulWidget {
    
    
  int? data;
  DirectSeedingNoticeDialog( {
    
    Key? key,this.data,}) : super(key: key);

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

class DirectSeedingNoticeDialogState extends State<DirectSeedingNoticeDialog>
    with TickerProviderStateMixin {
    
    
  String tip = '进场动画效果----';

  //动画控制器,可控制前进后退,重置
  late AnimationController _controllerOne;

  //第二个动画控制器
  late AnimationController _controllerTwo;

  //用于引导第一个动画:从右到左
  late Animation<Offset> _animationOne;

  //用于引导第二个动画:向左滑动
  late Animation<Offset> _animationTwo;

  late StreamSubscription<DirectSeedingNoticeEvent>? _liveEnterRoomAnimation;

  late StreamSubscription<HideGlobalDialog>? _hideGlobalDialog;

  //是否播放第一个动画
  bool firstAnimation = true;

  //动画显示的队列
  List<GroupUserBean> userEnterList = [];

  //默认是空闲false,有任务就是true
  bool animationState = false;

  //是否能显示弹窗
  bool canShowDialog = false;

  @override
  void initState() {
    
    
    //第一个动画:从右往左执行,动画的时间
    _controllerOne = AnimationController(
        duration: const Duration(milliseconds: 2000), vsync: this);

    _controllerTwo = AnimationController(
        duration: const Duration(milliseconds: 1000), vsync: this);

    _animationOne = Tween(begin: const Offset(2.5, 0), end: const Offset(0, 0))
        .animate(_controllerOne);

    //第二个动画:向左滑出去
    _animationTwo = Tween(begin: const Offset(0, 0), end: const Offset(-2.5, 0))
        .animate(_controllerTwo);

    //第一个动画监听
    _animationOne.addListener(() {
    
    
      if (_animationOne.status == AnimationStatus.completed) {
    
    
        //第一个动画结束
        PrintUtil.prints('$tip 第一个动画结束');
        //播放第二个动画
        firstAnimation = false;
        if (_controllerTwo.isCompleted || _controllerTwo.isDismissed) {
    
    
          Future.delayed(const Duration(seconds: 2), () {
    
    
            _controllerTwo.forward();
            PrintUtil.prints('$tip 第二个动画开始');
          });
        }
        mySetState(() {
    
    });
      } else if (_animationOne.status == AnimationStatus.forward) {
    
    
        PrintUtil.prints('$tip 第一个动画进行中');
        //第一个动画进行中
        animationState = true;
        //动画开始,任务状态为忙碌
        mySetState(() {
    
    });
      }
    });

    //第二个动画监听
    _animationTwo.addListener(() {
    
    
      if (_animationTwo.status == AnimationStatus.completed) {
    
    
        //第二个动画结束,重置位置
        PrintUtil.prints('$tip 第二个动画结束');
        //回到第一个动画
        firstAnimation = true;
        _controllerOne.reset();
        _controllerTwo.reset();
        //移除第一个数据
        if (userEnterList.isNotEmpty) {
    
    
          userEnterList.removeAt(0);
          if(userEnterList.isEmpty){
    
    
            //展示完就关闭全局弹窗
            if (_coverScreen != null) {
    
    
              _coverScreen?.hidden();
            }
          }
        }else{
    
    
          //展示完就关闭全局弹窗
          if (_coverScreen != null) {
    
    
            _coverScreen?.hidden();
          }
        }
        //任务闲下来了
        animationState = false;
        //展示下一个数据
        showAnimation();
        mySetState(() {
    
    });
      } else if (_animationTwo.status == AnimationStatus.forward) {
    
    
        PrintUtil.prints('$tip 第二个动画进行中');
        //动画开始,任务状态为忙碌
        mySetState(() {
    
    });
      }
    });

    _liveEnterRoomAnimation = EventBusUtil.listen((event) {
    
    
      //收到一个就添加一个数据,然后开始展示
      if (event.userInfo != null) {
    
    
        if(event.type!=null){
    
    
          if(event.type==1){
    
    
            userEnterList.add(event.userInfo!);
            showAnimation();
          }
        }
      }
      PrintUtil.prints('$tip 收到event数据${
    
    userEnterList.length}');
    });

    if(widget.data==1){
    
    
      EventBusUtil.fire(DirectSeedingNoticeEvent(
          type: 1,
          userInfo: GroupUserBean(
              userID: '',
              nickName: 'sdfhifud',
              avatar: 'df',
              avatarThumb: 'df'
          )));
    }

    //直播弹窗隐藏
    _hideGlobalDialog = EventBusUtil.listen((event) {
    
    
      if(event.type==1){
    
    
        canShowDialog = true;
        print('直播弹窗隐藏');
        mySetState((){
    
    });
      }
    });
    super.initState();
  }

  //取第一个数据展示,第二个动画播放完就删除数据
  showAnimation() {
    
    
    if (userEnterList.isNotEmpty) {
    
    
      PrintUtil.prints('$tip 展示数据时当前状态是$animationState  false是空闲');
      //空闲状态才给播放,防止添加数据是播放和播放完又调这个方法这两个混着了
      if (animationState == false) {
    
    
        if (_controllerOne.isCompleted || _controllerOne.isDismissed) {
    
    
          mySetState(() {
    
    });
          Future.delayed(Duration.zero, () {
    
    
            _controllerOne.forward();
            PrintUtil.prints('$tip 第一个动画启动 ${
    
    userEnterList.length}');
          });
        }
      }
    }
  }

  getAvatar() {
    
    
    String avatar = '';
    if (userEnterList.isNotEmpty) {
    
    
      if (userEnterList[0].avatarThumb != null) {
    
    
        avatar = userEnterList[0].avatarThumb ?? '';
      }
    }
    return avatar;
  }

  getNickName() {
    
    
    String name = '';
    if (userEnterList.isNotEmpty) {
    
    
      if (userEnterList[0].nickName != null) {
    
    
        name = userEnterList[0].nickName ?? '';
      }
    }
    return name;
  }

  //判断是否显示动画
  canShowAnimation() {
    
    
    bool show = false;
    if (getAvatar() != '' || getNickName() != '') {
    
    
      show = true;
    }
    return show;
  }

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

  @override
  void dispose() {
    
    
    print('直播弹窗结束');
    _controllerOne.dispose();
    _controllerTwo.dispose();
    if (_liveEnterRoomAnimation != null) {
    
    
      _liveEnterRoomAnimation!.cancel();
    }
    if (_coverScreen != null) {
    
    
      _coverScreen?.hidden();
    }
    if(_hideGlobalDialog!=null){
    
    
      _hideGlobalDialog!.cancel();
    }

    EventBusUtil.fire(HideGlobalDialog(1));
    print('有销毁直播通知弹窗');
    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    
    
    return Offstage(
      offstage: canShowDialog,
      child: Container(
        margin: EdgeInsets.only(top: Global.topHeight+30),
        alignment: Alignment.topCenter,
        child: SlideTransition(
            position: firstAnimation ? _animationOne : _animationTwo,
            child: canShowAnimation()
                ?
            GestureDetector(
              onTap: (){
    
    
                print('点击了直播通知弹窗');
              },
              child: Container(
                width: Global.screenWidth-30,
                      margin: const EdgeInsets.only(left: 15, top: 10, right: 15),
                      padding: const EdgeInsets.only(left: 15, right: 15),
                      height: 36,
                      decoration: BoxDecoration(
                        color: Colors.white,
                        borderRadius: BorderRadius.circular(15),
                      ),
                      child: Row(
                        children: <Widget>[
                          Container(
                            margin: const EdgeInsets.only(right: 10),
                            width: 15,
                            height: 15,
                            decoration: const BoxDecoration(
                              color: Colors.blue,
                            ),
                          ),
                          Expanded(
                            child:
                            MarqueeView(
                              child: Row(
                                children: [
                                  htmlText(),
                                  htmlText(),
                                  htmlText(),
                                  htmlText(),
                                  htmlText(),
                                  htmlText(),
                                ],
                              ),
                            ),
                          ),
                        ],
                      )),
            )
                : Container()),
      ),
    );
  }

  String textData = """
<p > This <b>num</b> is some text</p>
""";

  Widget htmlText() {
    
    
    return Container(
      margin: EdgeInsets.only(right: 10),
      child: Html(shrinkWrap: true, data: textData, style: {
    
    
        "html": Style(
            padding: EdgeInsets.all(0),
            margin: EdgeInsets.all(0),
            // backgroundColor: Colors.grey,
            textAlign: TextAlign.center),
        "body": Style(padding: EdgeInsets.all(0), margin: EdgeInsets.all(0)),
        "p": Style(
            padding: EdgeInsets.all(0),
            margin: EdgeInsets.all(0),
            fontSize: FontSize.rem(1.02),
            color: const Color(0xFF373737),
            fontWeight: FontWeight.w400),
        "p > b": Style(
            padding: EdgeInsets.all(0),
            margin: EdgeInsets.all(0),
            fontSize: FontSize.rem(1.02),
            color: const Color(0xFF373737),
            fontWeight: FontWeight.w600)
      }),
    );
  }
}


///展示
 CoverScreen? _coverScreen;

showLiveNoticeDialog() {
    
    
  if (_coverScreen != null && _coverScreen!.isShow) {
    
    
    // _coverScreen?.hidden();
    // coverScreen == null;
    EventBusUtil.fire(DirectSeedingNoticeEvent(
        type: 1,
        userInfo: GroupUserBean(
            userID: '',
            nickName: 'sdfhifud',
            avatar: 'df',
            avatarThumb: 'df'
        )));
  }else{
    
    
    _coverScreen = CoverScreen(
        child: DirectSeedingNoticeDialog(data:1), ignore: false);
    _coverScreen?.show();
  }
}

liveDialogDispose() {
    
    
  _coverScreen?.ondispose();
}

Guess you like

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