美文网首页
flutter手写一个非侵入式Drawer

flutter手写一个非侵入式Drawer

作者: 小吉快跑呀 | 来源:发表于2019-07-11 09:41 被阅读0次

    总体思路

    侧滑控件的实现原理: Flutter中Navigator是用来控制路由栈的,使用方式如下:

    Navigator.of(context).push(route);
    

    push接收一个Route,这个Route负责给出具体的widget,普通的Route在显示自己的page时会覆盖掉原本的页面,而PopupRoute就不会,他的效果类似于android中的popupWindow,自带蒙层。

    继承PopupRoute,修改参数,重写buildPage,在buildPage中返回一个带侧滑动画的widget

    class SlideWindow extends PopupRoute {
      ...
      @override
      Color get barrierColor => null;//去掉蒙层
    
      @override
      Widget buildPage(BuildContext context, Animation<double> animation,
          Animation<double> secondaryAnimation) {
      ...
        return slideWindowWidget;//page是全屏的
      }
    
    }
    

    布局

    这个widget是一个Stack结构,底层是全屏的Container蒙层,上层是一个带侧滑动画的内容widget,暂时只能是SizedBox,因为侧滑动画需要知道widget的宽度,而SizedBox是固定宽度的。

    Stack(children: <Widget>[
            //蒙层
          GestureDetector(
            onTap: widget.onTapOutsize,
            child: Container(
              width: MediaQuery.of(context).size.width,
              height: MediaQuery.of(context).size.height,
              color: colorAnimation.value,
            ),
          ),
            //内容层
          Container(
            width: MediaQuery.of(context).size.width,
            height: MediaQuery.of(context).size.height,
            alignment: Alignment.centerRight,
            //靠右竖直居中的内容widget
            child: Transform.translate(
              offset: Offset(widgetAnimation.value, 0),
              child: widget.child,
            ),
          )
        ]);
    

    动画

    在Flutter中,补间动画Tween的原理和Android中类似,规定value变化范围,value每次变化时setState(),根据最新的value去重建widget,在value变化的过程中,widget时不断重建的,某些属性也在不断被修改,这样就达到了动画效果。

    这里需要用到两种动画,一个是内容层的平移,一个是蒙层的颜色变化,代码如下,在初始化状态时设置动画

    @override
    void initState() {
      super.initState();
        //设置动画控制器
      controller = new AnimationController(
        duration: widget.duration,
        vsync: this,
      );
      //设置插值器
      Animation curve = CurvedAnimation(
          parent: controller, curve: Curves.fastLinearToSlowEaseIn);
      //设置内容层平移动画
      widgetAnimation =
          new Tween(begin: widget.child.width, end: 0.0).animate(curve)
            ..addListener(() {
              setState(() {});
            });
      //设置蒙层颜色动画
      colorAnimation = new ColorTween(
              begin: Colors.black.withOpacity(0),
              end: Colors.black.withOpacity(0.4))
          .animate(curve);
      //开始动画
      controller.forward();
    }
    

    然后内容需要用一个Transform变换控件包裹,这个控件可以对child做一些变换,例如移动位置

    Transform.translate(
      offset: Offset(widgetAnimation.value, 0),
      child: widget.child,
    )
    

    响应退出

    调用Navigator.pop()

    因为这是一个Route,所以是受Navigator控制的,代码中调用了Navigator.pop()时我们的页面是会消失的,这个消失不做处理的话是不带侧滑动画,也就是很难看,而在pop的过程中,系统会调用Route的didpop方法,所以可以重写这个方法在里面反转动画

    @override
    bool didPop(result) {
      slideWindowWidget.state.controller.reverse();//反转
      return super.didPop(result);
    }
    
    触摸了蒙层

    这种情况需要自己去控制,在蒙层上设置GestureDetector,在响应中调用Navigator.pop(),又回到第一种情况

    按到了物理返回键

    这种情况貌似在ios上不会出现,但是android设备是有返回键的,按了返回键后,系统同样会调用Navigator.pop(),还是回到第一种情况

    相关文章

      网友评论

          本文标题:flutter手写一个非侵入式Drawer

          本文链接:https://www.haomeiwen.com/subject/svtrkctx.html