代码之家  ›  专栏  ›  技术社区  ›  Nithin Sai

如何设置draggableScrollableSheet及其内容的动画?

  •  0
  • Nithin Sai  · 技术社区  · 1 年前

    a gif of what i am trying to build

    我正试图从 find my iOS上的应用程序。

    我用过 draggableScrollableSheet 但它不如上的那个好用 找到我的 .

    
    class DraggableSheet extends StatefulWidget {
      final Widget child;
      final String title;
      const DraggableSheet({super.key, required this.child, required this.title});
    
      @override
      State<DraggableSheet> createState() => _DraggableSheetState();
    }
    
    class _DraggableSheetState extends State<DraggableSheet> {
      final sheet = GlobalKey();
      final controller = DraggableScrollableController();
    
      @override
      void initState() {
        super.initState();
        controller.addListener(onChanged);
      }
    
      void onChanged() {
        final currentSize = controller.size;
        if (currentSize <= 0.10) collapse();
      }
    
      void collapse() => animateSheet(getSheet.snapSizes!.first);
    
      void anchor() => animateSheet(getSheet.snapSizes!.last);
    
      void expand() => animateSheet(getSheet.maxChildSize);
    
      void hide() => animateSheet(getSheet.minChildSize);
    
      void animateSheet(double size) {
        controller.animateTo(
          size,
          duration: const Duration(milliseconds: 100),
          curve: Curves.easeIn,
        );
      }
    
      @override
      void dispose() {
        super.dispose();
        controller.dispose();
      }
    
      DraggableScrollableSheet get getSheet =>
          (sheet.currentWidget as DraggableScrollableSheet);
    
      @override
      Widget build(BuildContext context) {
        return LayoutBuilder(builder: (context, constraints) {
          return DraggableScrollableSheet(
            key: sheet,
            snapAnimationDuration: const Duration(milliseconds: 100),
            initialChildSize: 0.157,
            maxChildSize: 0.93,
            minChildSize: 0,
            expand: true,
            snap: true,
            snapSizes: const [
              0.157,
              0.4,
              0.93,
            ],
            controller: controller,
            builder: (BuildContext context, ScrollController scrollController) {
              return DecoratedBox(
                decoration: BoxDecoration(
                  color: CupertinoTheme.of(context).scaffoldBackgroundColor,
                  boxShadow: const [
                    BoxShadow(
                      color: Colors.black12,
                      blurRadius: 10,
                      spreadRadius: 1,
                      offset: Offset(0, 1),
                    ),
                  ],
                  borderRadius: const BorderRadius.only(
                    topLeft: Radius.circular(10),
                    topRight: Radius.circular(10),
                  ),
                ),
                child: CustomScrollView(
                  controller: scrollController,
                  slivers: [
                    BottomSheetHeader(title: widget.title),
                    SliverToBoxAdapter(
                      child: widget.child,
                    ),
                  ],
                ),
              );
            },
          );
        });
      }
    }
    
    

    它缺少反弹捕捉动画,我不知道它们是如何显示按钮的 Add items 一个在第一次捕捉(大约一半屏幕大小),然后从主体展开(保持按钮在底部)。

    BottomSheetHeader

    class BottomSheetHeader extends StatelessWidget {
      final String title;
      const BottomSheetHeader({super.key, required this.title});
    
      @override
      Widget build(BuildContext context) {
        return SliverPersistentHeader(
          pinned: true,
          delegate: SliverAppBarDelegate(
            minHeight: 52,
            maxHeight: 52,
            child: Container(
              decoration: BoxDecoration(
                color: CupertinoTheme.of(context).scaffoldBackgroundColor,
              ),
              child: Column(
                children: [
                  Center(
                    child: Wrap(
                      children: <Widget>[
                        Container(
                          width: 36,
                          margin: const EdgeInsets.only(top: 4, bottom: 4),
                          height: 5,
                          decoration: const BoxDecoration(
                            color: Colors.black26,
                            shape: BoxShape.rectangle,
                            borderRadius: BorderRadius.all(Radius.circular(8.0)),
                          ),
                        ),
                      ],
                    ),
                  ),
                  Row(
                    children: [
                      Padding(
                        padding: const EdgeInsets.symmetric(horizontal: 20.0),
                        child: Text(
                          title,
                          style: const TextStyle(
                            fontSize: 20,
                            fontWeight: FontWeight.bold,
                          ),
                        ),
                      ),
                    ],
                  ),
                  const SizedBox(height: 8.0),
                  const Divider(
                    height: 0,
                  ),
                ],
              ),
            ),
          ),
        );
      }
    }
    
    class SliverAppBarDelegate extends SliverPersistentHeaderDelegate {
      SliverAppBarDelegate({
        required this.minHeight,
        required this.maxHeight,
        required this.child,
      });
      final double minHeight;
      final double maxHeight;
      final Widget child;
    
      @override
      double get minExtent => minHeight;
      @override
      double get maxExtent => max(maxHeight, minHeight);
    
      @override
      Widget build(
          BuildContext context, double shrinkOffset, bool overlapsContent) {
        return SizedBox.expand(child: child);
      }
    
      @override
      bool shouldRebuild(SliverAppBarDelegate oldDelegate) {
        return maxHeight != oldDelegate.maxHeight ||
            minHeight != oldDelegate.minHeight ||
            child != oldDelegate.child;
      }
    }
    
    

    有更好的方法吗?

    0 回复  |  直到 1 年前