How to overlap SliverList on a SliverAppBar

前端 未结 3 1643
孤街浪徒
孤街浪徒 2020-12-15 05:27

I\'m trying to overlap a SliverList a few pixels over the SliverAppBar. Similar to this post. I\'d like the image in the FlexibleSpaceBar

3条回答
  •  不知归路
    2020-12-15 05:45

    You can use the following widget which uses Stack and scroll listeners to achieve something like the screenshots. It's based on https://pub.dartlang.org/packages/sliver_fab.

    The widget:

    import 'package:flutter/material.dart';
    
    class DetailScaffold extends StatefulWidget {
      final ScrollController controller;
      final ScrollPhysics physics;
      final List slivers;
    
      final double expandedHeight;
    
      /// Changes edge behavior to account for [SliverAppBar.pinned].
      ///
      /// Hides the edge when the [ScrollController.offset] reaches the collapsed
      /// height of the [SliverAppBar] to prevent it from overlapping the app bar.
      final bool hasPinnedAppBar;
    
      DetailScaffold({
        @required this.expandedHeight,
        this.controller,
        this.physics,
        this.slivers,
        this.hasPinnedAppBar = false,
      }) {
        assert(expandedHeight != null);
        assert(hasPinnedAppBar != null);
      }
    
      @override
      _DetailScaffoldState createState() => _DetailScaffoldState();
    }
    
    class _DetailScaffoldState extends State {
      ScrollController ctrl;
    
      @override
      void initState() {
        super.initState();
    
        ctrl = widget.controller ?? ScrollController();
        ctrl.addListener(() => setState(() {}));
      }
    
      @override
      void dispose() {
        if (widget.controller == null) {
          ctrl.dispose();
        }
    
        super.dispose();
      }
    
      @override
      Widget build(BuildContext context) {
        return Stack(
          children: [
            CustomScrollView(
              controller: ctrl,
              physics: widget.physics,
              slivers: widget.slivers,
            ),
            _buildEdge(),
          ],
        );
      }
    
      _buildEdge() {
        var edgeHeight = 12.0;
        var paddingTop = MediaQuery.of(context).padding.top;
    
        var defaultOffset =
            (paddingTop + widget.expandedHeight) - edgeHeight;
    
        var top = defaultOffset;
        var edgeSize = edgeHeight;
    
        if (ctrl.hasClients) {
          double offset = ctrl.offset;
          top -= offset > 0 ? offset : 0;
    
          if (widget.hasPinnedAppBar) {
            // Hide edge to prevent overlapping the toolbar during scroll.
            var breakpoint =
                widget.expandedHeight - kToolbarHeight - edgeHeight;
    
            if (offset >= breakpoint) {
              edgeSize = edgeHeight - (offset - breakpoint);
              if (edgeSize < 0) {
                edgeSize = 0;
              }
    
              top += (edgeHeight - edgeSize);
            }
          }
        }
    
        return Positioned(
          top: top,
          left: 0,
          right: 0,
          child: Container(
            height: edgeSize,
            decoration: BoxDecoration(
              color: Theme.of(context).canvasColor,
              borderRadius: BorderRadius.vertical(
                top: Radius.circular(12),
              ),
            ),
          ),
        );
      }
    }
    

    Using it:

    class Home extends StatelessWidget {
      @override
      Widget build(BuildContext context) {
        var expandedHeight = 128.0;
    
        return DetailScaffold(
          expandedHeight: expandedHeight,
          slivers: [
            SliverAppBar(
              expandedHeight: expandedHeight,
              flexibleSpace: FlexibleSpaceBar(
                background: Container(color: Colors.purple),
              ),
            ),
            SliverList(
              delegate: SliverChildBuilderDelegate((_, i) {
                return ListTile(title: Text('Item $i'));
              }, childCount: 50),
            ),
          ],
        );
      }
    }
    

提交回复
热议问题