flutter 访问表单小部件内部模态底部表单的动画位置

4zcjmb1e  于 2023-03-13  发布在  Flutter
关注(0)|答案(1)|浏览(128)

内陆发展中国家:

我想根据路径的动画位置更改自定义模态表单的外观(即随着用户上下滑动表单而更改)。但是,我不想为了管理该控制器而将显示模态表单的任何UI小部件转换为StatefulWidget。相反,我想抽象出获取表单内表单动画位置的逻辑。

完整说明:

我有一个小部件用作模态底部表单,它包含一个表单句柄,我希望在用户更改底部表单的位置时动画显示句柄的宽度。据我所知,访问活动底部表单滚动位置的唯一方法是访问传递给showModalBottomSheettransitionAnimationController属性的AnimationController
但是,我不希望为了创建AnimationController而必须将调用showModalBottomSheet并显示此模态小部件的任何小部件转换为StatefulWidget,然后将控制器传递给showModalBottomSheet和模态小部件。因此我认为不可能在工作表的状态中抽象创建AnimationController,这意味着我需要另一种方法来访问路径的动画位置,而无需显式传递在父级中创建的AnimationController
板材手柄:

class _ModalSheetHandleState extends State<_ModalSheetHandle>
    with SingleTickerProviderStateMixin {
  final _handelHeight = Insets.xs;
  late final _controller = AnimationController(
    duration: Timings.short,
    vsync: this,
  );
  late final _animation =
      Tween<double>(begin: 35, end: 50).animate(_controller);

  @override
  void initState() {
    widget.modalSheetTransitionController.addListener(updateHandle);
    super.initState();
  }

  @override
  void dispose() {
    widget.modalSheetTransitionController.removeListener(updateHandle);
    _controller.dispose();
    super.dispose();
  }

  updateHandle() {
    if (widget.modalSheetTransitionController.isCompleted) {
      _controller.forward();
    } else if (!widget.modalSheetTransitionController.isCompleted &&
        _controller.isCompleted) {
      _controller.reverse();
    }
  }

  @override
  Widget build(BuildContext context) {
    return AnimatedBuilder(
      animation: _animation,
      builder: (_, __) => Container(
        width: _animation.value,
        height: _handelHeight,
        decoration: BoxDecoration(
          color: Colors.white,
          borderRadius: BorderRadius.circular(_handelHeight),
        ),
      ),
    );
  }
}

我现在做的

目前,我正在使用模态底层表单的widget中创建传递给showModalBottomSheetAnimationController,这与我想要做的相反,因为我想要在模态表单中抽象出这个控制器的有状态管理,下面是我目前正在做的事情:

// I *don't* want to convert any UI widget using the modal sheet to a stateful widget.
class _SomeUIElementState extends State<SomeUIElement> with SingleTickerProviderStateMixin {
  late final _modalSheetTransitionController = AnimationController(
    duration: Timings.med,
    vsync: this,
  );
  
  @override
  Widget build(BuildContext context) {
    return SomeWidget(
      child: Button(
        onTap: () {
          showModalBottomSheet(
            context: context,
            builder: (_) => ContextMenu(
              modalSheetTransitionAnimationController: _modalSheetTransitionController,
              actions: /*actions*/,
            ),
            transitionAnimationController: _modalSheetTransitionController,
          );
        },
      ),
    );
  }
}
rekjcdws

rekjcdws1#

找到了方法。不通过AnimationController访问路线动画,而是通过以下方式访问:

ModalRoute.of(context)!.animation!

因为路由的状态还没有初始化,所以监听器不能添加到模态的initState中的动画中,所以我认为监听器必须添加到构建方法中。

更新的模态句柄:

class _ModalSheetHandleState extends State<_ModalSheetHandle>
    with SingleTickerProviderStateMixin {
  final _handelHeight = Insets.xs;
  late final _controller = AnimationController(
    duration: Timings.short,
    vsync: this,
  );
  late final _animation =
      Tween<double>(begin: 35, end: 50).animate(_controller);
  bool routeListenerAdded = false;

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

  void updateHandle(Animation<double> routeAnimation) {
    if (routeAnimation.isCompleted) {
      _controller.forward();
    } else if (!routeAnimation.isCompleted && _controller.isCompleted) {
      _controller.reverse();
    }
  }

  @override
  Widget build(BuildContext context) {
    if(!routeListenerAdded) {
      final routeAnimation = ModalRoute.of(context)!.animation!;
      routeAnimation.addListener(() => updateHandle(routeAnimation));
      routeListenerAdded = true;
    }

    return AnimatedBuilder(
      animation: _controller,
      builder: (_, __) => Container(
        width: _animation.value,
        height: _handelHeight,
        decoration: BoxDecoration(
          color: Colors.white,
          borderRadius: BorderRadius.circular(_handelHeight),
        ),
      ),
    );
  }
}

相关问题