如果在Flutter Web项目中使用lottie动画

前言

lottie虽然支持很多平台,但是目前还没有flutter版,那么想要在flutter项目中使用lottie就需要通过调用原生sdk的方式。所以在flutter web项目中我们需要用lottie的js版本,那么具体如何使用呢?本文将会将lottie封装成一个组件,方便大家使用。

引入js

首先在index.html中添加lottie的js文件,如下:

<script type="text/javascript" src="js/lottie.js" acync></script>

ScriptElement

用ScriptElement封装lottie,如下:

var script = """
var lottieAnim = document.getElementById("lottie_anim");  //渲染模式如果是html,则不能直接这么获取;如果是canvas则可以
if(!lottieAnim){
  var roots = document.getElementsByTagName("flt-platform-view");
  for(var i = 0; i < roots.length; i++){
    var tmp = roots[i].shadowRoot.getElementById("lottie_anim");
    if(tmp){
      lottieAnim = tmp;
    }
  }
}

var lottieObj = lottie.loadAnimation({
container:lottieAnim,
renderer: 'svg',
loop:${widget.isLoop},
autoplay:${widget.isAutoPlay},
path:"assets/${widget.path}"
});
""";
ScriptElement scriptElement = new ScriptElement();
scriptElement.innerHtml = script;

首先我们需要获取到lottie_anim,这里需要注意flutter web的渲染模式(参考:Flutter Web:Shadow Root问题),如果是canvas模式则直接getElementById就可以获取;但是如果是html模式,因为Shadow Root问题无法直接获取到,所以在代码中如果通过getElementById获取是空的,就特殊处理一下。

然后通过loadAnimation来加载动画,这里需要三个参数loop、autoplay和path,因为打算封装成一个组件,所以这些参数我定义为widget的属性,从外面传进来。

交互

我们还需要添加一些交互,比如播放、暂停、停止等,如下:

var lottiePlay = function(){
    
    
  lottieObj.play();
}

var lottiePause = function(){
    
    
    lottieObj.pause();       
}

var lottieStop = function() {
    
    
    lottieObj.stop();
}

这样在flutter中,就可以通过js.context.callMethod来执行对应的方法,如下

void lottiePlay() {
  js.context.callMethod("lottiePlay");
}

void lottieStop() {
  js.context.callMethod("lottieStop");
}

void lottiePause() {
  js.context.callMethod("lottiePause");
}

还需要添加一个监听,来监听动画是否执行完成,以便执行后续操作,如下

// 动画播放完成触发
lottieObj.addEventListener('complete', lottieLoaded);

在flutter中注册这个监听,如下

js.context["lottieLoaded"] = lottieLoaded;
...
// 动画播放完成触发
void lottieLoaded(String args) {
    widget._animationListener?.call();
}

这里通过由外部来传入监听,以便各自进行处理。

HtmlElementView

然后将ScriptElement封装到HtmlElementView中以便使用,如下:

@override
Widget build(BuildContext context) {
  js.context["lottieLoaded"] = lottieLoaded;

  DivElement divElement = DivElement();
  divElement.id = "lottie_anim";

  StyleElement styleElement = StyleElement();
  styleElement.type = "text/css";
  styleElement.innerHtml = """
        html,
        body {
        }
        """;
  divElement.append(styleElement);

  var script = """
  ...
  """;
  ScriptElement scriptElement = new ScriptElement();
  scriptElement.innerHtml = script;
  divElement.append(scriptElement);

  String _divId = "lottieanim" + DateTime.now().toIso8601String();
  ui.platformViewRegistry.registerViewFactory(
    _divId,
    (int viewId) => divElement,
  );
  Widget _iframeWidget = HtmlElementView(
    key: UniqueKey(),
    viewType: _divId,
  );

  return SizedBox(child: _iframeWidget, width: widget.width, height: widget.height,);
}

注意这里viewType没有使用固定值,因为如果同时有多个动画的话,使用固定值会导致问题。

最后用一个SizedBox封装一下,设置一些动画的长宽即可,这样可以保证动画完整的显示,这个长宽同样由外部传入。

使用

封装成LottieWidget组件后,使用起来非常简单,如下:

LottieWidget(path,width, height, true, false, (){
  //动画结束处理
});

参数分别是:动画路径、宽度、长度、是否自动播放,是否循环播放,动画监听。

关注公众号:BennuCTech,获取更多干货!

猜你喜欢

转载自blog.csdn.net/chzphoenix/article/details/125151142
今日推荐