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

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

问题描述

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





我希望重叠的内容与上述GIF一样扑朔迷离



我的代码

  class DetailsPage扩展了StatefulWidget {
@override
_DetailsPage createState() => _DetailsPage();
}

类_DetailsPage扩展了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
小部件build(BuildContext context){
return Scaffold(
// backgroundColor:Colors.transparent,
body :NestedScrollView(
controller:_scrollController,
headerSliv​​erBuilder:(BuildContext context,bool innerBoxIsScrolled){
return< Widget> [
SliverAppBar(
expandHeight:250.0,
浮动:false,
亮度:Brightness.light,
固定:true,
//高程:0.0,
// backgroundColor:AppColors.colorCreateTripOrange,
backgroundColor:Colors.white,
操作:< Widget> [
GestureDetector(
onTap:(){
Navigator.of(context).pop();
},
子级:Padding(
padding:const EdgeInsets.only(right: 20.0),
子级:Image.asset(
'assets / images / close.png',
宽度:25.0,
高度:25.0,
),
),

],
开头:Padding(
padding:const EdgeInsets.only(left:20.0,top:0),
child: IconButton(
iconSize:25,
icon:Image.asset(
'assets / images / back.png',
宽度:25,
高度:25,
),
颜色:Colors.black,
onPressed :(){
Navigator.of(context).pop();
},
)),
flexibleSpace:FlexibleSpaceBar(
centerTitle:false,
crashMode:CollapseMode.parallax,
title:Text(isShrink?罗马:,
样式:TextStyle(
颜色:isShrink?Colors.black:Colors.white,
fontFamily:'bin_bold',
fontSize:18.0,
)),
背景:Image.network(
https://media.istockphoto.com/photos/great-colosseum-rome-italy-picture-id692334500\",
适合:BoxFit.cover,
)),
),

];
},
正文:Container(
//填充:const EdgeInsets.only(左:20.0,右:20.0,上:40.0),
装饰:BoxDecoration(
颜色:AppColors.colorWhite,
borderRadius:BorderRadius.all(Radius.circular(20)),
),
子级:列(
子级:< Widget> [
Expanded(
child:Container(
padding:
const EdgeInsets.only(left:20.0,right:20.0,top:40.0)),
装饰:BoxDecoration (
color:AppColors.colorWhite,
borderRadius:BorderRadius.all(Radius.circular(20)),
),
child:ListView(
children:< ; Widget> [
Column(
crossAxisAlignment:CrossAxisAlignment.start,
子代:< Widget> [
填充(
填充:EdgeInsets.symmetric(水平:15.0),
子代:文本(
罗马,
样式: TextStyle(
color:Colors.black,
fontFamily:'bin_bold',
fontSize:25.0),
),
),
填充(
padding:EdgeInsets.only(top:20,left:15,right:15),
child:Row(
children:< Widget> [
Image.asset(
'assets / images / calender.png',
宽度:25.0,
高度:25.0,
),
填充(
填充:const EdgeInsets.only(左:10.0),
子级:文本(
2020年3月6日至12日,
样式:TextStyle(
fontFamily:'bin',
fontSize:18,
颜色:AppColors.colorActivityGray),
),

] ,
),
),
Container(
宽度:double.infinity,
保证金:const EdgeInsets.only(
顶部:20.0,左侧: 20.0,右:30.0),
//填充:const EdgeInsets.only(左:20.0,右:20.0),
装饰:BoxDecoration(
颜色:AppColors.colorTripsGray,
borderRadius:BorderRadius.all(Radius.circular(20)) ,
边界:Border.all(color:AppColors.colorDivider),
),
子项:Column(
crossAxisAlignment:CrossAxisAlignment.start,
子项:<窗口小部件> [
填充(
填充:const EdgeInsets.only(
顶部:15.0,
底部:0.0,
左:20.0,
右: 20.0),
子级:文本(
Constants.region,
样式:TextStyle(
颜色:AppColors.colorLightBorderOrange,
fontFamily:'din',
fontSize:20),
),
),
填充(
填充:const EdgeInsets.only(
顶部:10.0,
底部:0.0,
左:20.0,
右: 20.0),
子级:Text(
Constants.firstName,
样式:TextStyle(
颜色:AppColors.colorCreateGreyTrans,
fontFamily:'din',
fontSize:20),
),
),
Padding(
padding:const EdgeInsets.only(
top: 10.0,下:0.0,左:0.0,右:00.0),
子级:Divider(),
),
填充(
padding:const EdgeInsets.only(
顶部:10.0,
底部:0.0,
左:20.0,
右:20.0),
子级:文本(
Constants.activities,
样式:TextStyle(
颜色:AppColors.colorLightBorderOrange,
fontFamily:'din',
fontSize:20),
),
),
填充(
填充:const EdgeInsets.only(
顶部:10.0,
底部:0.0,
左:20.0,
右:20.0),
子级:文本(
食品与饮料酒吧,必看景点,
样式:TextStyle(
颜色:AppColors.colorCreateGreyTrans,
fontFamily:'din',
fontSize:20),
),
),
填充(
填充:const EdgeInsets.only(
顶部:10.0,底部:0.0,左:0.0,右:00.0),
子级: Divider(),
),
填充(
padding:const EdgeInsets.only(
top:10.0,
bottom:0.0,
left:20.0 ,
右边:20.0),
孩子:文本(
Constants.noOfTravellers,
样式:TextStyle(
颜色:AppColors.colorLightBorderOrange,
fontFamily:'din',
fontSize:20),
),
),
填充(
填充:const EdgeInsets.only(
顶部:10.0,
底部:0.0,
左:20.0,
右:20.0),
儿童:Text(
2 Adults,1 kid,
样式:TextStyle (
color:AppColors.colorCreateGreyTrans,
fontFamily:'din',
fontSize:20),
),
),
填充(
padding:const EdgeInsets.only(
上:10.0,下:0.0,左:0.0,右:00.0),
子级:Divider(),
),
填充(
填充:const EdgeInsets.only(
顶部:10.0,
底部:0.0,
左:20.0,
右:20.0),
子代:文字(
Constants.email,
样式:TextStyle(
颜色:AppColors.colorLightBorderOrange,
fontFamily:'din',
fontSize:20),
),
),
填充(
填充:const EdgeInsets.only(
顶部:10.0,
底部:10.0,
左:20.0,
右: 20.0),
子级:Text(
kim.john12@gmail.com,
样式:TextStyle(
颜色:AppColors.colorCreateGreyTrans,
fontFamily:'din',
fontSize:20),
),
),
],
),
),
],

],
),
),
),
容器(
宽度:double.infinity,
保证金:const EdgeInsets.only(顶部:20.0),
填充:const EdgeInsets.all(10.0),
装饰:BoxDecoration(
颜色:AppColors.colorWhite,
borderRadius:BorderRadius.all(Radius.circular(40)),
border:Border.all(color:AppColors.colorDivider,width:2.0),
),
child:Center(
子级:Wrap(
子级:< Widget> [
MaterialButton(
padding:const EdgeInsets.symmetric(
水平:40,垂直:20),
textColor :Colors.black,
颜色:AppColors.colorWhite,
孩子:Text(
Constants.messageTripDesigner,
样式:TextStyle(
fontFamily:'din_bold',
fontSize:Constants.regionFontSize),
),
形状:RoundedRectangleBorder(
borderRadius:BorderRadius.circular(30.0),
侧面:BorderSide(
color :AppColors.colorLightBorderOrange,
width:2),
),
onPressed:(){
Navigator.of(context).pop();
},

],
),
),

],
),
),
),
);
}
}


类MySliverAppBar扩展了SliverPersistentHeaderDelegate {
最后的double ExpandedHeight;

MySliverAppBar({@ required this.expandedHeight});

@override
窗口小部件构建(
BuildContext上下文,double收缩偏移量,布尔重叠内容){
return Stack(
fit:StackFit.expand,
溢出:Overflow.visible,
子级:[
Image.network(
https://images.pexels.com/photos/396547/pexels-photo-396547.jpeg? auto = compress& cs = tinysrgb& dpr = 1& w = 500,
fit:BoxFit.cover,
),
Center(
子级:Opacity(
不透明度:shrinkOffset / expandedHeight,
子元素:Text(
MySliverAppBar,
样式:TextStyle(
颜色:Colors.white,
fontWeight:FontWeight.w700 ,
fontSize:23,
),
),
),
),
],
);
}

@override
double get maxExtent => expandHeight;

@override
double get minExtent => kToolbarHeight;

@override
bool shouldRebuild(SliverPersistentHeaderDelegate oldDelegate)=>真正;
}

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






  • 步骤




    1. 堆叠 DraggableScrollableSheet 内的> AppBar

    2. 使用 DraggableScrollableNotification 更新标题高度和
      AppBar 阴影。

    在这里

      import'package:flutter / material.dart '; 

    void main(){
    runApp(MaterialApp(debugShowCheckedModeBanner:false,home:HomePage()));
    }

    类主页扩展StatefulWidget {
    @override
    State< StatefulWidget> createState()=> _HomePageState();
    }

    类_HomePageState扩展了State< HomePage>
    和SingleTickerProviderStateMixin {
    final ValueNotifier< double> headerNegativeOffset = ValueNotifier< double>(0);
    final ValueNotifier< bool> appbarShadow = ValueNotifier< bool>(false);

    最终双倍maxHeaderHeight = 250.0;
    final double minHeaderHeight = 56.0;
    final double bodyContentRatioMin = .8;
    final double bodyContentRatioMax = 1.0;

    ///必须介于身体含量比率的最小值和最大值之间。
    final double bodyContentRatioParallax = .9;

    @override
    void dispose(){
    headerNegativeOffset.dispose();
    appbarShadow.dispose();
    super.dispose();
    }

    @override
    窗口小部件build(BuildContext context){
    return Scaffold(
    //仅用于状态栏颜色
    appBar: PreferredSize(
    preferredSize:Size.fromHeight(0.0),
    子对象:AppBar(
    backgroundColor:Colors.pink,
    高程:0.0,
    ),
    ),
    正文:Stack(
    子项:< Widget> [
    Stack(子项:[
    容器(
    子项:ValueListenableBuilder< double>(
    valueListenable:headerNegativeOffset,
    生成器:(context,offset,child){
    return Transform.translate(
    offset:Offset(0,offset * -1),
    child :SizedBox(
    高度:maxHeaderHeight,
    子级:容器(
    颜色:Colors.pink,
    ),
    ),
    );
    })),
    NotificationListener< DraggableScrollableNotification>(
    onNotification:(通知){
    if(notification.extent == bodyContentRatioMin){
    appbarShadow.value = false ;;
    headerNegativeOffset.value = 0;
    }否则,如果(notification.extent == bodyContentRatioMax){
    appbarShadow.value = true;
    headerNegativeOffset.value =
    maxHeaderHeight -minHeaderHeight;
    }否则{
    double newValue =(maxHeaderHeight-minHeaderHeight)-
    ((maxHeaderHeight-minHeaderHeight)*
    ((bodyContentRatioParallax-(notification.extent))/
    (bodyContentRatioMax-
    bodyContentRatioParallax)));
    appbarShadow .value = false;
    if(newValue> = maxHeaderHeight-minHeaderHeight){
    appbarShadow.value = true;
    newValue = maxHeaderHeight-minHeaderHeight;
    }否则,如果(newValue< 0){
    appbarShadow.value = false;
    newValue = 0;
    }
    headerNegativeOffset.value = newValue;
    }

    返回true;
    },
    子项:Stack(
    子项:< Widget> [
    DraggableScrollableSheet(
    initialChildSize:bodyContentRatioMin,
    minChildSize:bodyContentRatioMin,
    maxChildSize:bodyContentRatioMax,
    builder:(BuildContext context,
    ScrollController scrollController){
    return Stack(
    children:< Widget> [
    Container(
    对齐方式:AlignmentDirectional.center,
    填充:EdgeInsets.only(
    左:16.0,右:16.0,顶部:16.0),
    子级:Material(
    type:MaterialType。画布,
    颜色:Colors.white,
    海拔:2.0,
    borderRadius:BorderRadius.only(
    top左:Radius.circular(24.0),
    top右:Radius.circular(24.0),
    ),
    子代:ListView.builder(
    控制器:scrollController,
    itemCount:200,
    itemBuilder:(BuildContext context,int index){
    return ListTile(title:Text('Item $指数'));
    },
    ),
    ),
    ),
    ],
    );
    },
    ),
    ],
    ),

    ]),
    位置(剩余
    :0.0,
    右边:0.0,
    顶部:0.0,
    子元素:ValueListenableBuilder< bool>(
    valueListenable:appbarShadow,
    builder:(context,value,child){
    /// appbar的默认高度是56.0。您也可以
    ////使用自定义高度的自定义小部件
    return AppBar(
    backgroundColor:Colors.pink ,
    标题:Text( Notes),
    海拔:值?2.0:0.0,
    );
    }),
    ),
    ] ,
    ),
    抽屉:Drawer(),
    );
    }
    }

    观看实时演示此处


    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天全站免登陆