Flutter 类抽屉效果动画实现。

2,241 阅读1分钟

效果:

竖向抽屉:

    

横向抽屉:



实现思路

  •  在STACK 容器里创建3个页面.
    具体代码如下:

    child: Stack(        
                children: <Widget>[        
                 Container(            
                   color: widget?.backgroundColor,             
                   child: buildContent(),         
                  ),        
                buildTop(),        
               buildRight(),        
            ],),

  •  通过监听onVerticalDragUpdate和onHorizontalDragUpdate 获取属相和横向滑动的坐标信息
            onVerticalDragUpdate: _inContent
                ? (details) {
                    calculateOffsetY(
                        details,
                        ((widget?.topPopConfig?.topMaxHeight ?? 0) <= 0
                                ? _height
                                : (widget?.topPopConfig?.topMaxHeight ?? 0)) -
                            (widget?.topPopConfig?.topMinHeight ?? 0));
                  }
                : null,
    
    
    
    

  • 用Transform包裹抽屉实现根据滑动位移而偏移

    class TopPop extends StatelessWidget {
      final double offsetY;
      final double height;
      final double minHeight;
      final double parentHeight;
      final Widget child;
      final Color backgroupColor;
      final bool needDarker;
      final GestureTapCallback onDarkerTap;
    
      TopPop(
          {Key key,
          this.offsetY = 0.0,
          this.height = 0.0,
          this.minHeight = 0.0,
          this.parentHeight = 0.0,
          this.child,
          this.backgroupColor,
          this.needDarker = false,
          this.onDarkerTap})
          : super(key: key);
    
      @override
      Widget build(BuildContext context) {
        double tempOffsetY = 0.0;
        if (offsetY >= 0.0) {
          tempOffsetY = max(0.0, (parentHeight - minHeight));
        } else {
          tempOffsetY = offsetY + max(0.0, (parentHeight - minHeight));
        }
        double opacity = offsetY.abs() / height;
        debugPrint(
            '++++++++offsetY = ${offsetY.toString()}+++++++++opacity = ${opacity.toString()}+++++parentHeight= ${parentHeight.toString()}++ height=${height.toString()}++++++++++minHeight=${minHeight.toString()}+++++++++++++++++++');
        return Stack(
          children: <Widget>[
            needDarker && opacity > 0
                ? GestureDetector(
                    onTap: onDarkerTap,
                    child: Opacity(
                      opacity: opacity,
                      child: Container(
                        width: MediaQuery.of(context).size.width,
                        height: parentHeight,
                        color: Color(0x4C000000),
                      ),
                    ),
                  )
                : Container(),
            Transform.translate(
                offset: Offset(0, tempOffsetY),
                child: Container(
                  color: backgroupColor ?? Color(0x00000000),
                  width: MediaQuery.of(context).size.width,
                  height: height,
                  child: child,
                ))
          ],
        );
      }
    }
    
    
    
    
  • 监听拖动结束事件,并实现自动滑动动画。

            onVerticalDragEnd: (_) {
              if (_offsetY.abs() >
                      (widget?.topPopConfig?.topAutoAnimDistance ?? 20) &&
                  topDirection == AxisDirection.up) {
                animateToTop();
              } else {
                animateToBottom();
              }
            },
    
    
    

  • 监听拖动开始事件,重置自动滑动动画

            onVerticalDragStart: (_) {
              _animationControllerX?.stop();
              _animationControllerY?.stop();
            },
    
    
    

代码地址:
github.com/sail-coder/…