Search code examples
flutterflutter-animationflutter-sliver

Scaling content on drag down in Flutter


I want to achieve the following behavior in Flutter.

this

Do you know if there is a built-in widget in Flutter that provides that functionality out of the box?


Solution

  • try this CustomScrollView:

    LayoutBuilder(
      builder: (context, constraints) {
        return CustomScrollView(
          slivers: <Widget>[
            SliverPersistentHeader(
              pinned: true,
              delegate: Delegate(),
            ),
            SliverToBoxAdapter(
              child: Container(
                decoration: BoxDecoration(
                  borderRadius:  BorderRadius.all(Radius.circular(30)),
                  border:  Border.all(
                    width: 2.0,
                    color:  Colors.deepPurple,
                  ),
                ),
                height: constraints.biggest.height,
                child: Center(
                  child: Text('Drag me down (or up) in order to see (or hide) the red icon on the top',
                    textAlign: TextAlign.center,
                    textScaleFactor: 5.0,
                  ),
                ),
              ),
            ),
          ],
        );
      }
    ),
    

    the "delegate" class is as follows:

    class Delegate extends SliverPersistentHeaderDelegate {
      @override
      Widget build(BuildContext context, double shrinkOffset, bool overlapsContent) {
        // print(shrinkOffset);
        return Opacity(
          opacity: 1 - shrinkOffset / maxExtent,
          child: FittedBox(child: Icon(Icons.alarm, color: Colors.red,), fit: BoxFit.contain),
        );
      }
      @override double get maxExtent => 300;
      @override double get minExtent => 100;
      @override bool shouldRebuild(SliverPersistentHeaderDelegate oldDelegate) => true;
    }
    

    now try to drag the text up and down

    EDIT: and this is a little modification to be similar like your example:

    LayoutBuilder(
      builder: (context, constraints) {
        return CustomScrollView(
          slivers: <Widget>[
            SliverPersistentHeader(
              pinned: true,
              delegate: Delegate(),
            ),
            SliverToBoxAdapter(
              child: Container(
                padding: EdgeInsets.only(top: 75),
                height: constraints.biggest.height,
                child: Text('Drag me down (or up) in order to make the red icon bigger (or smaller)',
                  textAlign: TextAlign.center,
                  textScaleFactor: 5.0,
                ),
              ),
            ),
          ],
        );
      }
    ),
    

    and the modified delegate class:

    class Delegate extends SliverPersistentHeaderDelegate {
      @override
      Widget build(BuildContext context, double shrinkOffset, bool overlapsContent) {
        // print(shrinkOffset);
        return OverflowBox(
          maxHeight: 400,
          alignment: Alignment.topCenter,
          child: Container(
            height: 400 - shrinkOffset,
            child:  FittedBox(child: Icon(Icons.alarm, color: Colors.red,), fit: BoxFit.contain),
          ), 
        );
      }
      @override double get maxExtent => 300;
      @override double get minExtent => 1;
      @override bool shouldRebuild(SliverPersistentHeaderDelegate oldDelegate) => true;
    }