Flutter:如何允许内容重叠 SliverAppBar? [英] Flutter : how Allow content to overlap SliverAppBar?

查看:71
本文介绍了Flutter:如何允许内容重叠 SliverAppBar?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

在 android 中,我们使用 app:behavior_overlapTop="64dp" 来实现这一点

我希望在颤动中与上面的 GIF 相同的重叠内容

我的代码

类 DetailsPage 扩展 StatefulWidget {@覆盖_DetailsPage createState() =>_DetailsPage();}类 _DetailsPage 扩展了 State<DetailsPage>{@覆盖无效初始化状态(){super.initState();SystemChrome.setPreferredOrientations([DeviceOrientation.portraitUp,DeviceOrientation.portraitDown,]);_scrollController = 滚动控制器();_scrollController.addListener(_scrollListener);}滚动控制器_滚动控制器;布尔最后状态=真;_scrollListener() {if (isShrink != lastStatus) {设置状态((){lastStatus = isShrink;});}}布尔获取 isShrink {return _scrollController.hasClients &&_scrollController.offset >(250 - kToolbarHeight);}@覆盖无效处置(){_scrollController.removeListener(_scrollListener);super.dispose();}@覆盖小部件构建(BuildContext 上下文){返回脚手架(//backgroundColor: Colors.transparent,正文:嵌套滚动视图(控制器:_scrollController,headerSliv​​erBuilder: (BuildContext context, bool innerBoxIsScrolled) {返回<小部件>[SliverAppBar(扩展高度:250.0,浮动:假,亮度:Brightness.light,固定:真的,//海拔:0.0,//backgroundColor: AppColors.colorCreateTripOrange,背景颜色:颜色.白色,动作:<小部件>[手势检测器(点按:(){Navigator.of(context).pop();},孩子:填充(填充:const EdgeInsets.only(右:20.0),孩子:Image.asset('资产/图像/close.png',宽度:25.0,高度:25.0,),),)],领先:填充(填充:const EdgeInsets.only(左:20.0,上:0),孩子:图标按钮(图标大小:25,图标:Image.asset('资产/图像/back.png',宽度:25,身高:25,),颜色:颜色.黑色,按下:(){Navigator.of(context).pop();},)),弹性空间:弹性空间条(中心标题:假,collapseMode: CollapseMode.parallax,标题:文本(isShrink?罗马":",样式:文本样式(颜色:isShrink ?颜色.黑色:颜色.白色,fontFamily: 'bin_bold',字体大小:18.0,)),背景:Image.network("https://media.istockphoto.com/photos/great-colosseum-rome-italy-picture-id692334500",适合:BoxFit.cover,)),),];},身体:容器(//padding: const EdgeInsets.only(left: 20.0, right: 20.0, top: 40.0),装饰:盒子装饰(颜色:AppColors.colorWhite,边界半径:边界半径.all(半径.圆形(20)),),孩子:列(孩子们:<小部件>[展开(孩子:容器(填充:const EdgeInsets.only(左:20.0,右:20.0,上:40.0),装饰:盒子装饰(颜色:AppColors.colorWhite,边界半径:边界半径.all(半径.圆形(20)),),孩子:列表视图(孩子们:<小部件>[柱子(crossAxisAlignment:CrossAxisAlignment.start,孩子们:<小部件>[填充(填充:EdgeInsets.symmetric(水平:15.0),孩子:文本(罗马",样式:文本样式(颜色:颜色.黑色,fontFamily: 'bin_bold',字体大小:25.0),),),填充(填充:EdgeInsets.only(顶部:20,左侧:15,右侧:15),孩子:行(孩子们:<小部件>[图片.asset('assets/images/calender.png',宽度:25.0,高度:25.0,),填充(填充:const EdgeInsets.only(左:10.0),孩子:文本(2020年3月6-12日",样式:文本样式(fontFamily: 'bin',字体大小:18,颜色:AppColors.colorActivityGray),),)],),),容器(宽度:双无限,边距:常量 EdgeInsets.only(上:20.0,左:20.0,右:30.0),//padding: const EdgeInsets.only(left: 20.0, right: 20.0),装饰:盒子装饰(颜色:AppColors.colorTripsGray,边界半径:边界半径.all(半径.圆形(20)),边框:Border.all(颜色:AppColors.colorDivider),),孩子:列(crossAxisAlignment:CrossAxisAlignment.start,孩子们:<小部件>[填充(填充:const EdgeInsets.only(最高:15.0,底部:0.0,左:20.0,右:20.0),孩子:文本(常量.区域,样式:文本样式(颜色:AppColors.colorLightBorderOrange,fontFamily: 'din',字体大小:20),),),填充(填充:const EdgeInsets.only(最高:10.0,底部:0.0,左:20.0,右:20.0),孩子:文本(常量.firstName,样式:文本样式(颜色:AppColors.colorCreateGreyTrans,fontFamily: 'din',字体大小:20),),),填充(填充:const EdgeInsets.only(上:10.0,下:0.0,左:0.0,右:00.0),孩子:分频器(),),填充(填充:const EdgeInsets.only(最高:10.0,底部:0.0,左:20.0,右:20.0),孩子:文本(常量.活动,样式:文本样式(颜色:AppColors.colorLightBorderOrange,fontFamily: 'din',字体大小:20),),),填充(填充:const EdgeInsets.only(最高:10.0,底部:0.0,左:20.0,右:20.0),孩子:文本(美食与酒吧,必看景点",样式:文本样式(颜色:AppColors.colorCreateGreyTrans,fontFamily: 'din',字体大小:20),),),填充(填充:const EdgeInsets.only(上:10.0,下:0.0,左:0.0,右:00.0),孩子:分频器(),),填充(填充:const EdgeInsets.only(最高:10.0,底部:0.0,左:20.0,右:20.0),孩子:文本(常量.noOfTravellers,样式:文本样式(颜色:AppColors.colorLightBorderOrange,fontFamily: 'din',字体大小:20),),),填充(填充:const EdgeInsets.only(最高:10.0,底部:0.0,左:20.0,右:20.0),孩子:文本(2 名成人,1 名儿童",样式:文本样式(颜色:AppColors.colorCreateGreyTrans,fontFamily: 'din',字体大小:20),),),填充(填充:const EdgeInsets.only(上:10.0,下:0.0,左:0.0,右:00.0),孩子:分频器(),),填充(填充:const EdgeInsets.only(最高:10.0,底部:0.0,左:20.0,右:20.0),孩子:文本(常量.email,样式:文本样式(颜色:AppColors.colorLightBorderOrange,fontFamily: 'din',字体大小:20),),),填充(填充:const EdgeInsets.only(最高:10.0,底部:10.0,左:20.0,右:20.0),孩子:文本("kim.john12@gmail.com",样式:文本样式(颜色:AppColors.colorCreateGreyTrans,fontFamily: 'din',字体大小:20),),),],),),],)],),),),容器(宽度:双无限,边距:const EdgeInsets.only(顶部:20.0),填充:常量 EdgeInsets.all(10.0),装饰:盒子装饰(颜色:AppColors.colorWhite,边界半径:边界半径.all(半径.圆形(40)),边框:Border.all(颜色:AppColors.colorDivider,宽度:2.0),),孩子:中心(孩子:包裹(孩子们:<小部件>[材质按钮(填充: const EdgeInsets.symmetric(水平:40,垂直:20),文本颜色:颜色.黑色,颜色:AppColors.colorWhite,孩子:文本(常量.messageTripDesigner,样式:文本样式(fontFamily: 'din_bold',fontSize: 常量.regionFontSize),),形状:圆角矩形边框(边界半径:边界半径.圆形(30.0),边:边界边(颜色:AppColors.colorLightBorderOrange,宽度:2),),按下:(){Navigator.of(context).pop();},)],),),)],),),),);}}类 MySliverAppBar 扩展 SliverPersistentHeaderDelegate {最终双expandHeight;MySliverAppBar({@required this.expandedHeight});@覆盖小部件构建(BuildContext context, double shrinkOffset, bool overlaysContent) {返回堆栈(适合:StackFit.expand,溢出:溢出.可见,孩子们: [图像.网络("https://images.pexels.com/photos/396547/pexels-photo-396547.jpeg?auto=compress&cs=tinysrgb&dpr=1&w=500",适合:BoxFit.cover,),中心(孩子:不透明度(不透明度:shrinkOffset/expandHeight,孩子:文本("MySliverAppBar",样式:文本样式(颜色:颜色.白色,字体重量:字体重量.w700,字体大小:23,),),),),],);}@覆盖双重获取最大范围=>扩展高度;@覆盖双重获取 minExtent =>k工具栏高度;@覆盖bool shouldRebuild(SliverPersistentHeaderDelegate oldDelegate) =>真的;}

以下是我目前尝试过的一些帖子

  • 步骤

    1. DraggableScrollableSheetAppBar 堆叠在主体内脚手架
    2. 使用 DraggableScrollableNotification 更新标题高度和AppBar 阴影.

    给你

     import 'package:flutter/material.dart';无效的主要(){runApp(MaterialApp(debugShowCheckedModeBanner: false, home: HomePage()));}类 HomePage 扩展 StatefulWidget {@覆盖状态<StatefulWidget>创建状态()=>_HomePageState();}class _HomePageState 扩展了 State与 SingleTickerProviderStateMixin {最终值通知器<double>headerNegativeOffset = ValueNotifier<double>(0);final ValueNotifier<bool>appbarShadow = ValueNotifier(false);最终双 maxHeaderHeight = 250.0;最终双 minHeaderHeight = 56.0;最终双 bodyContentRatioMin = .8;最终双 bodyContentRatioMax = 1.0;///必须在正文内容比率的最小值和最大值之间.最终双 bodyContentRatioParallax = .9;@覆盖无效处置(){headerNegativeOffset.dispose();appbarShadow.dispose();super.dispose();}@覆盖小部件构建(BuildContext 上下文){返回脚手架(//仅用于状态栏颜色appBar: PreferredSize(首选尺寸:Size.fromHeight(0.0),孩子:AppBar(背景颜色:颜色.粉红色,海拔:0.0,),),正文:堆栈(孩子们:<小部件>[堆栈(儿童:[容器(孩子:ValueListenableBuilder<double>(valueListenable: headerNegativeOffset,builder: (context, offset, child) {返回变换.翻译(偏移量:偏移量(0,偏移量 * -1),孩子:大小框(高度:maxHeaderHeight,孩子:容器(颜色:颜色.粉红色,),),);})),NotificationListener<DraggableScrollableNotification>(onNotification:(通知){if (notification.extent == bodyContentRatioMin) {appbarShadow.value = false;headerNegativeOffset.value = 0;} else if (notification.extent == bodyContentRatioMax) {appbarShadow.value = true;headerNegativeOffset.value =maxHeaderHeight - minHeaderHeight;} 别的 {双 newValue = (maxHeaderHeight - minHeaderHeight) -((maxHeaderHeight - minHeaderHeight) *((bodyContentRatioParallax - (notification.extent))/(bodyContentRatioMax -bodyContentRatioParallax)));appbarShadow.value = false;if (newValue >= maxHeaderHeight - minHeaderHeight) {appbarShadow.value = true;newValue = maxHeaderHeight - minHeaderHeight;} else if (newValue < 0) {appbarShadow.value = false;新值 = 0;}headerNegativeOffset.value = newValue;}返回真;},孩子:堆栈(孩子们:<小部件>[DraggableScrollableSheet(initialChildSize: bodyContentRatioMin,minChildSize: bodyContentRatioMin,maxChildSize: bodyContentRatioMax,构建器:(BuildContext上下文,滚动控制器滚动控制器){返回堆栈(孩子们:<小部件>[容器(对齐:AlignmentDirectional.center,填充:EdgeInsets.only(左:16.0,右:16.0,上:16.0),孩子:材料(类型:MaterialType.canvas,颜色:颜色.白色,海拔:2.0,边界半径:边界半径.only(左上角:半径.圆形(24.0),右上:半径.圆形(24.0),),孩子:ListView.builder(控制器:滚动控制器,项目数:200,itemBuilder: (BuildContext context, int index) {return ListTile(title: Text('Item $index'));},),),),],);},),],),)]),定位(左:0.0,右:0.0,顶部:0.0,孩子:ValueListenableBuilder<bool>(valueListenable: appbarShadow,构建器:(上下文,值,子){///appbar 的默认高度是 56.0.你也可以///如果需要,可以使用具有自定义高度的自定义小部件.返回应用栏(背景颜色:颜色.粉红色,标题:文本(笔记"),海拔:价值?2.0:0.0,);}),),],),抽屉:抽屉(),);}}

    查看现场演示这里.

    In android we are using app:behavior_overlapTop="64dp" to achieve this

    I want overlap content same like above GIF in flutter

    My code

    class DetailsPage extends StatefulWidget {
      @override
      _DetailsPage createState() => _DetailsPage();
    }
    
    class _DetailsPage extends State<DetailsPage> {
      @override
      void initState() {
        super.initState();
        SystemChrome.setPreferredOrientations([
          DeviceOrientation.portraitUp,
          DeviceOrientation.portraitDown,
        ]);
        _scrollController = ScrollController();
        _scrollController.addListener(_scrollListener);
    
      }
    
      ScrollController _scrollController;
    
      bool lastStatus = true;
    
      _scrollListener() {
        if (isShrink != lastStatus) {
          setState(() {
            lastStatus = isShrink;
          });
        }
      }
    
      bool get isShrink {
        return _scrollController.hasClients &&
            _scrollController.offset > (250 - kToolbarHeight);
      }
    
      @override
      void dispose() {
        _scrollController.removeListener(_scrollListener);
        super.dispose();
      }
    
      @override
      Widget build(BuildContext context) {
        return Scaffold(
    //      backgroundColor: Colors.transparent,
          body: NestedScrollView(
            controller: _scrollController,
            headerSliverBuilder: (BuildContext context, bool innerBoxIsScrolled) {
              return <Widget>[
                SliverAppBar(
                  expandedHeight: 250.0,
                  floating: false,
                  brightness: Brightness.light,
                  pinned: true,
    //              elevation: 0.0,
    //              backgroundColor: AppColors.colorCreateTripOrange,
                  backgroundColor: Colors.white,
                  actions: <Widget>[
                    GestureDetector(
                      onTap: () {
                        Navigator.of(context).pop();
                      },
                      child: Padding(
                        padding: const EdgeInsets.only(right: 20.0),
                        child: Image.asset(
                          'assets/images/close.png',
                          width: 25.0,
                          height: 25.0,
                        ),
                      ),
                    )
                  ],
                  leading: Padding(
                      padding: const EdgeInsets.only(left: 20.0, top: 0),
                      child: IconButton(
                        iconSize: 25,
                        icon: Image.asset(
                          'assets/images/back.png',
                          width: 25,
                          height: 25,
                        ),
                        color: Colors.black,
                        onPressed: () {
                          Navigator.of(context).pop();
                        },
                      )),
                  flexibleSpace: FlexibleSpaceBar(
                      centerTitle: false,
                      collapseMode: CollapseMode.parallax,
                      title: Text(isShrink ? "Rome" : "",
                          style: TextStyle(
                            color: isShrink ? Colors.black : Colors.white,
                            fontFamily: 'bin_bold',
                            fontSize: 18.0,
                          )),
                      background: Image.network(
                        "https://media.istockphoto.com/photos/great-colosseum-rome-italy-picture-id692334500",
                        fit: BoxFit.cover,
                      )),
                ),
    
              ];
            },
            body: Container(
    //          padding: const EdgeInsets.only(left: 20.0, right: 20.0, top: 40.0),
              decoration: BoxDecoration(
                color: AppColors.colorWhite,
                borderRadius: BorderRadius.all(Radius.circular(20)),
              ),
              child: Column(
                children: <Widget>[
                  Expanded(
                    child: Container(
                      padding:
                      const EdgeInsets.only(left: 20.0, right: 20.0, top: 40.0),
                      decoration: BoxDecoration(
                        color: AppColors.colorWhite,
                        borderRadius: BorderRadius.all(Radius.circular(20)),
                      ),
                      child: ListView(
                        children: <Widget>[
                          Column(
                            crossAxisAlignment: CrossAxisAlignment.start,
                            children: <Widget>[
                              Padding(
                                padding: EdgeInsets.symmetric(horizontal: 15.0),
                                child: Text(
                                  "Rome",
                                  style: TextStyle(
                                      color: Colors.black,
                                      fontFamily: 'bin_bold',
                                      fontSize: 25.0),
                                ),
                              ),
                              Padding(
                                padding: EdgeInsets.only(top: 20, left: 15, right: 15),
                                child: Row(
                                  children: <Widget>[
                                    Image.asset(
                                      'assets/images/calender.png',
                                      width: 25.0,
                                      height: 25.0,
                                    ),
                                    Padding(
                                      padding: const EdgeInsets.only(left: 10.0),
                                      child: Text(
                                        "March 6-12, 2020",
                                        style: TextStyle(
                                            fontFamily: 'bin',
                                            fontSize: 18,
                                            color: AppColors.colorActivityGray),
                                      ),
                                    )
                                  ],
                                ),
                              ),
                              Container(
                                width: double.infinity,
                                margin: const EdgeInsets.only(
                                    top: 20.0, left: 20.0, right: 30.0),
    //                padding: const EdgeInsets.only(left: 20.0, right: 20.0),
                                decoration: BoxDecoration(
                                  color: AppColors.colorTripsGray,
                                  borderRadius: BorderRadius.all(Radius.circular(20)),
                                  border: Border.all(color: AppColors.colorDivider),
                                ),
                                child: Column(
                                  crossAxisAlignment: CrossAxisAlignment.start,
                                  children: <Widget>[
                                    Padding(
                                      padding: const EdgeInsets.only(
                                          top: 15.0,
                                          bottom: 0.0,
                                          left: 20.0,
                                          right: 20.0),
                                      child: Text(
                                        Constants.region,
                                        style: TextStyle(
                                            color: AppColors.colorLightBorderOrange,
                                            fontFamily: 'din',
                                            fontSize: 20),
                                      ),
                                    ),
                                    Padding(
                                      padding: const EdgeInsets.only(
                                          top: 10.0,
                                          bottom: 0.0,
                                          left: 20.0,
                                          right: 20.0),
                                      child: Text(
                                        Constants.firstName,
                                        style: TextStyle(
                                            color: AppColors.colorCreateGreyTrans,
                                            fontFamily: 'din',
                                            fontSize: 20),
                                      ),
                                    ),
                                    Padding(
                                      padding: const EdgeInsets.only(
                                          top: 10.0, bottom: 0.0, left: 0.0, right: 00.0),
                                      child: Divider(),
                                    ),
                                    Padding(
                                      padding: const EdgeInsets.only(
                                          top: 10.0,
                                          bottom: 0.0,
                                          left: 20.0,
                                          right: 20.0),
                                      child: Text(
                                        Constants.activities,
                                        style: TextStyle(
                                            color: AppColors.colorLightBorderOrange,
                                            fontFamily: 'din',
                                            fontSize: 20),
                                      ),
                                    ),
                                    Padding(
                                      padding: const EdgeInsets.only(
                                          top: 10.0,
                                          bottom: 0.0,
                                          left: 20.0,
                                          right: 20.0),
                                      child: Text(
                                        "Food & Bar, Must See Attractions",
                                        style: TextStyle(
                                            color: AppColors.colorCreateGreyTrans,
                                            fontFamily: 'din',
                                            fontSize: 20),
                                      ),
                                    ),
                                    Padding(
                                      padding: const EdgeInsets.only(
                                          top: 10.0, bottom: 0.0, left: 0.0, right: 00.0),
                                      child: Divider(),
                                    ),
                                    Padding(
                                      padding: const EdgeInsets.only(
                                          top: 10.0,
                                          bottom: 0.0,
                                          left: 20.0,
                                          right: 20.0),
                                      child: Text(
                                        Constants.noOfTravellers,
                                        style: TextStyle(
                                            color: AppColors.colorLightBorderOrange,
                                            fontFamily: 'din',
                                            fontSize: 20),
                                      ),
                                    ),
                                    Padding(
                                      padding: const EdgeInsets.only(
                                          top: 10.0,
                                          bottom: 0.0,
                                          left: 20.0,
                                          right: 20.0),
                                      child: Text(
                                        "2 Adults, 1 kid",
                                        style: TextStyle(
                                            color: AppColors.colorCreateGreyTrans,
                                            fontFamily: 'din',
                                            fontSize: 20),
                                      ),
                                    ),
                                    Padding(
                                      padding: const EdgeInsets.only(
                                          top: 10.0, bottom: 0.0, left: 0.0, right: 00.0),
                                      child: Divider(),
                                    ),
                                    Padding(
                                      padding: const EdgeInsets.only(
                                          top: 10.0,
                                          bottom: 0.0,
                                          left: 20.0,
                                          right: 20.0),
                                      child: Text(
                                        Constants.email,
                                        style: TextStyle(
                                            color: AppColors.colorLightBorderOrange,
                                            fontFamily: 'din',
                                            fontSize: 20),
                                      ),
                                    ),
                                    Padding(
                                      padding: const EdgeInsets.only(
                                          top: 10.0,
                                          bottom: 10.0,
                                          left: 20.0,
                                          right: 20.0),
                                      child: Text(
                                        "kim.john12@gmail.com",
                                        style: TextStyle(
                                            color: AppColors.colorCreateGreyTrans,
                                            fontFamily: 'din',
                                            fontSize: 20),
                                      ),
                                    ),
                                  ],
                                ),
                              ),
                            ],
                          )
                        ],
                      ),
                    ),
                  ),
                  Container(
                    width: double.infinity,
                    margin: const EdgeInsets.only(top: 20.0),
                    padding: const EdgeInsets.all(10.0),
                    decoration: BoxDecoration(
                      color: AppColors.colorWhite,
                      borderRadius: BorderRadius.all(Radius.circular(40)),
                      border: Border.all(color: AppColors.colorDivider, width: 2.0),
                    ),
                    child: Center(
                      child: Wrap(
                        children: <Widget>[
                          MaterialButton(
                            padding: const EdgeInsets.symmetric(
                                horizontal: 40, vertical: 20),
                            textColor: Colors.black,
                            color: AppColors.colorWhite,
                            child: Text(
                              Constants.messageTripDesigner,
                              style: TextStyle(
                                  fontFamily: 'din_bold',
                                  fontSize: Constants.regionFontSize),
                            ),
                            shape: RoundedRectangleBorder(
                              borderRadius: BorderRadius.circular(30.0),
                              side: BorderSide(
                                  color: AppColors.colorLightBorderOrange,
                                  width: 2),
                            ),
                            onPressed: () {
                              Navigator.of(context).pop();
                            },
                          )
                        ],
                      ),
                    ),
                  )
                ],
              ),
            ),
          ),
        );
      }
    }
    
    
    class MySliverAppBar extends SliverPersistentHeaderDelegate {
      final double expandedHeight;
    
      MySliverAppBar({@required this.expandedHeight});
    
      @override
      Widget build(
          BuildContext context, double shrinkOffset, bool overlapsContent) {
        return Stack(
          fit: StackFit.expand,
          overflow: Overflow.visible,
          children: [
            Image.network(
              "https://images.pexels.com/photos/396547/pexels-photo-396547.jpeg?auto=compress&cs=tinysrgb&dpr=1&w=500",
              fit: BoxFit.cover,
            ),
            Center(
              child: Opacity(
                opacity: shrinkOffset / expandedHeight,
                child: Text(
                  "MySliverAppBar",
                  style: TextStyle(
                    color: Colors.white,
                    fontWeight: FontWeight.w700,
                    fontSize: 23,
                  ),
                ),
              ),
            ),
          ],
        );
      }
    
      @override
      double get maxExtent => expandedHeight;
    
      @override
      double get minExtent => kToolbarHeight;
    
      @override
      bool shouldRebuild(SliverPersistentHeaderDelegate oldDelegate) => true;
    }
    

    Below are some post that i have tried so far

    If need more information please do let me know. Thanks in advance. Your efforts will be appreciated.

    解决方案

    You can make the App bar scrolling with overlapping content like flexible space by using any of the following combo depending upon your use case.

    1. ListView with Scroll notification
    2. SliverList with Scroll notification
    3. DraggableScrollableSheet with DraggableScrollableNotification

    Well, Here I am going with the easiest one, DraggableScrollableSheet which allows to scroll and drag simultaneously to create the desired effect.

    Steps

    1. Stack the DraggableScrollableSheet and the AppBar inside the body of the Scaffold
    2. Use DraggableScrollableNotification to update the header height and AppBar shadow.

    Here you go

     import 'package:flutter/material.dart';
    
    void main() {
      runApp(MaterialApp(debugShowCheckedModeBanner: false, home: HomePage()));
    }
    
    class HomePage extends StatefulWidget {
      @override
      State<StatefulWidget> createState() => _HomePageState();
    }
    
    class _HomePageState extends State<HomePage>
        with SingleTickerProviderStateMixin {
      final ValueNotifier<double> headerNegativeOffset = ValueNotifier<double>(0);
      final ValueNotifier<bool> appbarShadow = ValueNotifier<bool>(false);
    
      final double maxHeaderHeight = 250.0;
      final double minHeaderHeight = 56.0;
      final double bodyContentRatioMin = .8;
      final double bodyContentRatioMax = 1.0;
    
      ///must be between min and max values of body content ratio.
      final double bodyContentRatioParallax = .9;
    
      @override
      void dispose() {
        headerNegativeOffset.dispose();
        appbarShadow.dispose();
        super.dispose();
      }
    
      @override
      Widget build(BuildContext context) {
        return Scaffold(
          //just for status bar color
          appBar: PreferredSize(
            preferredSize: Size.fromHeight(0.0),
            child: AppBar(
              backgroundColor: Colors.pink,
              elevation: 0.0,
            ),
          ),
          body: Stack(
            children: <Widget>[
              Stack(children: [
                Container(
                    child: ValueListenableBuilder<double>(
                        valueListenable: headerNegativeOffset,
                        builder: (context, offset, child) {
                          return Transform.translate(
                            offset: Offset(0, offset * -1),
                            child: SizedBox(
                              height: maxHeaderHeight,
                              child: Container(
                                color: Colors.pink,
                              ),
                            ),
                          );
                        })),
                NotificationListener<DraggableScrollableNotification>(
                  onNotification: (notification) {
                    if (notification.extent == bodyContentRatioMin) {
                      appbarShadow.value = false;
                      headerNegativeOffset.value = 0;
                    } else if (notification.extent == bodyContentRatioMax) {
                      appbarShadow.value = true;
                      headerNegativeOffset.value =
                          maxHeaderHeight - minHeaderHeight;
                    } else {
                      double newValue = (maxHeaderHeight - minHeaderHeight) -
                          ((maxHeaderHeight - minHeaderHeight) *
                              ((bodyContentRatioParallax - (notification.extent)) /
                                  (bodyContentRatioMax -
                                      bodyContentRatioParallax)));
                      appbarShadow.value = false;
                      if (newValue >= maxHeaderHeight - minHeaderHeight) {
                        appbarShadow.value = true;
                        newValue = maxHeaderHeight - minHeaderHeight;
                      } else if (newValue < 0) {
                        appbarShadow.value = false;
                        newValue = 0;
                      }
                      headerNegativeOffset.value = newValue;
                    }
    
                    return true;
                  },
                  child: Stack(
                    children: <Widget>[
                      DraggableScrollableSheet(
                        initialChildSize: bodyContentRatioMin,
                        minChildSize: bodyContentRatioMin,
                        maxChildSize: bodyContentRatioMax,
                        builder: (BuildContext context,
                            ScrollController scrollController) {
                          return Stack(
                            children: <Widget>[
                              Container(
                                alignment: AlignmentDirectional.center,
                                padding: EdgeInsets.only(
                                    left: 16.0, right: 16.0, top: 16.0),
                                child: Material(
                                  type: MaterialType.canvas,
                                  color: Colors.white,
                                  elevation: 2.0,
                                  borderRadius: BorderRadius.only(
                                    topLeft: Radius.circular(24.0),
                                    topRight: Radius.circular(24.0),
                                  ),
                                  child: ListView.builder(
                                    controller: scrollController,
                                    itemCount: 200,
                                    itemBuilder: (BuildContext context, int index) {
                                      return ListTile(title: Text('Item $index'));
                                    },
                                  ),
                                ),
                              ),
                            ],
                          );
                        },
                      ),
                    ],
                  ),
                )
              ]),
              Positioned(
                left: 0.0,
                right: 0.0,
                top: 0.0,
                child: ValueListenableBuilder<bool>(
                    valueListenable: appbarShadow,
                    builder: (context, value, child) {
                      ///default height of appbar is 56.0. You can also
                      ///use a custom widget with custom height if you want.
                      return AppBar(
                        backgroundColor: Colors.pink,
                        title: Text("Notes"),
                        elevation: value ? 2.0 : 0.0,
                      );
                    }),
              ),
            ],
          ),
          drawer: Drawer(),
        );
      }
    }
    

    See the live demo here.

    这篇关于Flutter:如何允许内容重叠 SliverAppBar?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆