使用 Transform 对 Stack 内底部小部件上的顶部小部件进行动画处理导致问题

时间:2021-06-01 10:26:04

标签: flutter flutter-layout flutter-animation

我无法在 Body() 上为 CustomDrawer() 小部件设置动画,两者都在 Stack() 中。我想要做的是在 Body() 上为我的 CustomDrawer() 小部件制作动画(就像 Discord 聊天页面一样)我已经实现了从左到右的滑动,但是我遇到了问题从右到左动画。正如您在下面的 gif 中看到的那样。

enter image description here

我使用 Transform()GestureDetector() 将我的 Body() 小部件从左到右转换。 但是当我想从右向左滑动时出现问题。

我想要的:我希望当用户从左向右滑动时会显示 Drawer1,当用户从右向左滑动时会显示 Drawer2。 Drawer 1 和 2 只不过是一个在 Column() 内有 2 Row() 的单个小部件。 我正在使用 DragStartDetails 检测基于 startDetails.globalPosition.dx 的滑动,这会给我 x 轴的位置。

问题:但是当我尝试更改从右向左滑动的逻辑时,它在 GIF 中给了我这种笨拙的效果。

这是我的 AppDrawer() 小部件,其中发生了所有事情。

  class AppDrawer extends StatefulWidget {
  final Widget child;
  AppDrawer({
    key,
    required this.child,
  }) : super(key: key);

  static _AppDrawerState? of(BuildContext context) =>
      context.findAncestorStateOfType<_AppDrawerState>();

  @override
  _AppDrawerState createState() => _AppDrawerState();
}

class _AppDrawerState extends State<AppDrawer>
    with SingleTickerProviderStateMixin {
  static Duration duration = const Duration(milliseconds: 300);
  late AnimationController _controller;
  static double maxSlide = 255;
  static const dragRightStartVal = 260;
  static var dragLeftStartVal = maxSlide - 20;
  static bool shouldDrag = false;
  bool isDraggingFromRight = false;
  bool isDraggingFromLeft = false;

  @override
  void initState() {
    _controller =
        AnimationController(vsync: this, duration: _AppDrawerState.duration);
    super.initState();
  }

  void close() => _controller.reverse();

  void open() => _controller.forward();

  void toggle() {
    if (_controller.isCompleted) {
      close();
    } else {
      open();
    }
  }

  @override
  void dispose() {
    _controller.dispose();
    super.dispose();
  }

  void _onDragStart(DragStartDetails startDetails) {
    // print("dragstart");
    // print("startdetails $startDetails");
    isDraggingFromLeft = _controller.isDismissed &&
        startDetails.globalPosition.dx < dragRightStartVal;
    // print("isDraggingFromLeft${isDraggingFromLeft}");
    isDraggingFromRight = _controller.isDismissed
        ? startDetails.globalPosition.dx > -dragLeftStartVal
        : _controller.isCompleted &&
            startDetails.globalPosition.dx > dragLeftStartVal;
    // print("isDraggingFromRight${isDraggingFromRight}");
    shouldDrag = isDraggingFromLeft || isDraggingFromRight;
    // print("shouldDrag${shouldDrag}");
    // print("controller${_controller.isDismissed}${_controller.isCompleted}");
  }

  void _onDragUpdate(DragUpdateDetails updateDetails) {
    if (shouldDrag == false) {
      return;
    }
    double delta = updateDetails.primaryDelta! / maxSlide;
    _controller.value += delta;
  }

  void _onDragEnd(DragEndDetails dragEndDetails) {
    if (_controller.isDismissed || _controller.isCompleted) {
      return;
    }

    double _kMinFlingVelocity = 365.0;
    double dragVelocity = dragEndDetails.velocity.pixelsPerSecond.dx.abs();

    if (dragVelocity >= _kMinFlingVelocity) {
      double visualVelocityInPx = dragEndDetails.velocity.pixelsPerSecond.dx /
          MediaQuery.of(context).size.width;
      _controller.fling(velocity: visualVelocityInPx);
    } else if (_controller.value < 0.5) {
      close();
    } else {
      open();
    }
  }

  @override
  Widget build(BuildContext context) {
    return GestureDetector(
      onHorizontalDragStart: _onDragStart,
      onHorizontalDragUpdate: _onDragUpdate,
      onHorizontalDragEnd: _onDragEnd,
      child: AnimatedBuilder(
        animation: _controller,
        builder: (BuildContext context, _) {
          double animationVal = isDraggingFromRight && _controller.isCompleted
              ? -_controller.value
              : _controller.value;
          double translateVal =
              animationVal * MediaQuery.of(context).size.width * 0.5;
          return Stack(
            children: <Widget>[
              CustomDrawer(),
              Transform(
                alignment: Alignment.centerLeft,
                transform: Matrix4.identity()..translate(translateVal),
                child: GestureDetector(
                  onTap: () {
                    if (_controller.isCompleted) {
                      close();
                    }
                  },
                  child: widget.child,
                ),
              ),
            ],
          );
        },
      ),
    );
  }
}

class CustomDrawer extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Material(
      color: Colors.black38,
      child: SafeArea(
        child: Theme(
          data: ThemeData(
            brightness: Brightness.dark,
          ),
          child: SizedBox(
            width: MediaQuery.of(context).size.width,
            child: Row(
              mainAxisAlignment: MainAxisAlignment.spaceBetween,
              children: [
                Column(
                  children: <Widget>[
                    Container(
                      padding: const EdgeInsets.all(16),
                      child: const Text('Drawer 1',
                          style: TextStyle(fontSize: 30, color: Colors.white)),
                    ),
                    Container(
                      width: MediaQuery.of(context).size.width * 0.5,
                      child: const ListTile(
                        leading: Icon(Icons.home),
                        title: Text('Home'),
                      ),
                    ),
                    Container(
                      width: MediaQuery.of(context).size.width * 0.5,
                      child: const ListTile(
                        leading: Icon(Icons.home),
                        title: Text('Favourite'),
                      ),
                    ),
                    Container(
                      width: MediaQuery.of(context).size.width * 0.5,
                      child: const ListTile(
                        leading: Icon(Icons.home),
                        title: Text('Store'),
                      ),
                    ),
                  ],
                ),
                Column(
                  children: <Widget>[
                    Container(
                      padding: const EdgeInsets.all(16),
                      child: const Text('Drawer 2',
                          style: TextStyle(fontSize: 30, color: Colors.white)),
                    ),
                    Container(
                      width: MediaQuery.of(context).size.width * 0.5,
                      child: const ListTile(
                        leading: Icon(Icons.home),
                        title: Text('Settings'),
                      ),
                    ),
                    Container(
                      width: MediaQuery.of(context).size.width * 0.5,
                      child: const ListTile(
                        leading: Icon(Icons.home),
                        title: Text('Socials'),
                      ),
                    ),
                    Container(
                      width: MediaQuery.of(context).size.width * 0.5,
                      child: const ListTile(
                        leading: Icon(Icons.home),
                        title: Text('Feedback'),
                      ),
                    ),
                  ],
                ),
              ],
            ),
          ),
        ),
      ),
    );
  }
}

任何人都可以帮忙或提供相同的提示吗?谢谢!

0 个答案:

没有答案