如何将小部件从小条展开到全屏并折叠回来?

问题描述 投票:0回答:1

我需要这个结果(该应用程序仅作为示例) enter image description here

我尝试使用 BottomSheet、modal_bottom_sheet 和各种类似的库,但它们完全隐藏了小部件。我希望它作为一条小条保留在导航栏上方,并且能够通过滑动或点击将其拉出。

flutter dart flutter-animation bottom-sheet flutter-showmodalbottomsheet
1个回答
0
投票

这只是实现您的设计的一个想法,如果您想退出,我将使用 GetX 来实现它,我认为您应该尝试

GestureDetector
来了解拖动偏移

ps.也许这不是最佳实践,所以我只是说只是一个想法希望这会有所帮助

结果

页面小部件

class PlaygroundPage extends StatelessWidget {
  const PlaygroundPage({super.key});

  @override
  Widget build(BuildContext context) {
    return GetBuilder<PlaygroundPageController>(
      global: false,
      init: PlaygroundPageController(),
      builder: (controller) => Scaffold(
        backgroundColor: AppColors.white,
        bottomNavigationBar: _Bottombar(
          controller: controller,
        ),
        body: Padding(
          padding: EdgeInsets.fromLTRB(0, Get.mediaQuery.padding.top, 0, 0),
          child: Column(
            children: [
              ToButton(
                onPressed: () {
                  Get.back();
                },
                child: Container(
                  width: 200,
                  height: 50,
                  color: AppColors.green1,
                  child: const Text('back'),
                ),
              )
            ],
          ),
        ),
      ),
    );
  }
}

class _Bottombar extends StatelessWidget {
  final PlaygroundPageController controller;
  const _Bottombar({
    required this.controller,
    Key? key,
  }) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return PopScope(
      canPop: false,
      child: Container(
        clipBehavior: Clip.antiAlias,
        decoration: const BoxDecoration(
          boxShadow: [AppShadow.shadowTop],
        ),
        height: (72 + Get.mediaQuery.padding.bottom + 70) + (controller.animation.value * 500),
        child: Stack(
          children: [
            Positioned(
              bottom: 0,
              child: Column(
                mainAxisSize: MainAxisSize.min,
                children: [
                  ToButton(
                    onPressed: () {
                      controller.isCollapsed.toggle();
                      controller.handleToggleExpanded();
                    },
                    child: Container(
                      decoration: BoxDecoration(
                        borderRadius: BorderRadius.only(
                          topLeft: Radius.circular(0 + (24 * controller.animation.value)),
                          topRight: Radius.circular(0 + (24 * controller.animation.value)),
                        ),
                        color: AppColors.red,
                      ),
                      width: Get.width,
                      height: (72 + Get.mediaQuery.padding.bottom + 70),
                      child: Column(
                        mainAxisAlignment: MainAxisAlignment.start,
                        crossAxisAlignment: CrossAxisAlignment.center,
                        children: [
                          Container(
                            margin: const EdgeInsets.fromLTRB(0, 8, 0, 0),
                            width: 100,
                            height: 10,
                            decoration: BoxDecoration(
                              borderRadius: BorderRadius.circular(24),
                              color: AppColors.grey2,
                            ),
                          )
                        ],
                      ),
                    ),
                  ),
                  SizeTransition(
                    axisAlignment: 1.0,
                    sizeFactor: controller.animation,
                    child: Container(
                      width: Get.width,
                      height: 500,
                      color: AppColors.green1,
                    ),
                  ),
                ],
              ),
            ),
            Positioned(
              bottom: ((72 + Get.mediaQuery.padding.bottom) * controller.reverseAnimation.value) - (72 + Get.mediaQuery.padding.bottom),
              child: Container(
                padding: const EdgeInsets.fromLTRB(0, 16, 0, 0),
                width: Get.width,
                height: (72 + Get.mediaQuery.padding.bottom),
                decoration: const BoxDecoration(
                  color: AppColors.grey,
                  boxShadow: [AppShadow.shadowTop],
                ),
                child: Row(
                  mainAxisAlignment: MainAxisAlignment.center,
                  crossAxisAlignment: CrossAxisAlignment.start,
                  children: [
                    Container(
                      color: Colors.red,
                      width: sizing(20),
                      height: sizing(20),
                      padding: const EdgeInsets.fromLTRB(4, 8, 4, 0).toResponsive(),
                    ),
                    SizedBox(width: sizing(20)),
                    Container(
                      color: Colors.red,
                      width: sizing(20),
                      height: sizing(20),
                      padding: const EdgeInsets.fromLTRB(4, 8, 4, 0).toResponsive(),
                    ),
                    SizedBox(width: sizing(20)),
                    Container(
                      color: Colors.red,
                      width: sizing(20),
                      height: sizing(20),
                      padding: const EdgeInsets.fromLTRB(4, 8, 4, 0).toResponsive(),
                    ),
                    SizedBox(width: sizing(20)),
                    Container(
                      color: Colors.red,
                      width: sizing(20),
                      height: sizing(20),
                      padding: const EdgeInsets.fromLTRB(4, 8, 4, 0).toResponsive(),
                    ),
                    SizedBox(width: sizing(20)),
                    Container(
                      color: Colors.red,
                      width: sizing(20),
                      height: sizing(20),
                      padding: const EdgeInsets.fromLTRB(4, 8, 4, 0).toResponsive(),
                    ),
                  ],
                ),
              ),
            ),
          ],
        ),
      ),
    );
  }
}

控制器

class PlaygroundPageController extends GetxController with GetTickerProviderStateMixin {
  late AnimationController expandController;
  late AnimationController collapseController;

  late Animation<double> animation;
  late Animation<double> reverseAnimation;

  final isCollapsed = true.obs;

  @override
  void onInit() {
    super.onInit();
    prepareAnimations();
    prepareReverseAnimations();
  }

  void handleToggleExpanded() {
    if (!isCollapsed.value) {
      expandController.forward();
      collapseController.forward();
    } else {
      expandController.reverse();
      collapseController.reverse();
    }
  }

  void prepareAnimations() {
    expandController = AnimationController(
      vsync: this,
      duration: const Duration(
        milliseconds: 1500,
      ),
    );
    Animation<double> curve = CurvedAnimation(
      parent: expandController,
      curve: Curves.fastOutSlowIn,
    );
    animation = Tween(begin: 0.0, end: 1.0).animate(curve)..addListener(() => refresh());
  }

  void prepareReverseAnimations() {
    collapseController = AnimationController(
      vsync: this,
      duration: const Duration(
        milliseconds: 1500,
      ),
    );
    Animation<double> curve = CurvedAnimation(
      parent: collapseController,
      curve: Curves.fastOutSlowIn,
    );
    reverseAnimation = Tween(begin: 1.0, end: 0.0).animate(curve)..addListener(() => refresh());
  }
}
© www.soinside.com 2019 - 2024. All rights reserved.