flutter SliverPersistentHeader子组件透明度渐变【滑动悬停appbar添加自定义组件的透明度】

在开发flutter悬停头部中,发现一个问题。

我们通常使用SliverAppBar(),去实现悬停的功能,在使用appbar的时候满足不了我们的需求,就需要自定义,

如下:在title中写了一个搜索框的功能,但是我发现在上滑隐藏的时候,icon有渐变效果,包括普通的text都有渐变的效果,像我写的TextField则没有这种效果。

也就是浅入浅出的效果。如图:

return NestedScrollView(
      headerSliverBuilder: (BuildContext context, bool innerBoxIsScrolled) {
        return <Widget>[
          SliverAppBar(
       //这是自定义的头部布局 title: Container( child: Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ Expanded( child: Icon( Iconfont.zhiboicon, ), flex:
0, ), Expanded( child: Container( margin: EdgeInsets.fromLTRB(10, 0, 10, 0), child: TextField( style: TextStyle( fontSize: 13, color: ColorKit.hexToColor('#979797')), decoration: InputDecoration( contentPadding: EdgeInsets.all(5), isCollapsed: true, prefixIcon: Container( margin: EdgeInsets.fromLTRB(10, 0, 5, 0), child: Icon( Iconfont.sousuoicon, size: 15, color: ColorKit.hexToColor('#999999'), ), ), //添加内部左边图标 prefixIconConstraints: BoxConstraints(), fillColor: ColorKit.hexToColor('#F6F6F6'), filled: true, hintText: '请输入搜索内容', hintStyle: TextStyle(fontSize: 13), border: OutlineInputBorder( borderRadius: BorderRadius.circular(20), borderSide: BorderSide.none, ), ), onChanged: (text) { print('onchanged+$text'); }, onSubmitted: (text) { print('onSubmitted+$text'); }, ), ), flex: 1, ), Expanded( child: Icon( Iconfont.addicon, color: Colors.blue, ), flex: 0, ), ], ), ), pinned: true, floating: true, forceElevated: innerBoxIsScrolled, bottom: PreferredSize( preferredSize: Size(double.infinity, 48), child: Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ Expanded( flex: 1, child: Container( // height: 48, child: TabBar( indicatorSize: TabBarIndicatorSize.label, isScrollable: true, controller: _tabController, tabs: _tabbarTitile.map((e) { return Tab( text: e, ); }).toList(), ), )), Expanded( flex: 0, child: Container( margin: EdgeInsets.fromLTRB(10, 0, 10, 0), child: Icon(Iconfont.gengduoicon), )) ], ), ), ), ]; }, body: TabBarView( controller: _tabController, //tabbar控制器 children: _tabbarView, ), );

作为一个flutter都小白,每次遇到问题都喜欢网上找现成的,但是flutter都文章少的可怜。

后来还是下定决定自己研究一下,看了很多文章,这个方法可行,就是单独把头部的布局拿出来用SliverPersistentHeader来实现。

关于SliverPersistentHeader的介绍请看这里:没错是我,点我

“控件当滚动到边缘时根据滚动的距离缩小高度,有点类似 SliverAppBar 的背景效果”

我写的自定义SliverPersistentHeaderDelegate。如果你也是小白,看到这里不是很明白。别担心,我会把整个代码和使用方法写上来的。

上代码:

自己写一个类,然后继承SliverPersistentHeaderDelegate。

写几个常用的入参,比如我写的是传入的child,也就是传入的小部件,这里用PreferredSize,为什么用这个呢,因为这个组件高度是固定的,也就是自己去设置内容的高度。在maxExtent和minExtent中需要获取这个高度。必须是固定高度(我经过好多天研究出来的,可能是知识范围有限,如果有问题,可以帮我指出改正)。 

第二个是islucency,是布尔类型,在外部传入是否滚动时淡入淡出。不知道为啥就写上了,可能是习惯,为了以后有不用这个功能的时候。

第三个是背景颜色。这里单独传入一个背景色。有两种原因,一种是如果直接在child中定义背景色,那么淡入淡出的时候,背景也会虚化。另外一种就是在入参中添加backgroundColor,背景不会虚化,虚化的是内容的小部件,大家也可以看到下面Opacity是嵌套在Container中的。不传参数默认白色,当然这个属性也不会影响小部件自己设置背景色。

import 'dart:math' as math;
import 'package:flutter/material.dart';

class CommonSliverHeaderDelegate extends SliverPersistentHeaderDelegate{
  PreferredSize child;//传入preferredsize组件,因为此组件需要固定高度
  bool islucency;//入参 是否更加滑动变化透明度,true,false
  Color backgroundColor;//需要设置的背景色
  CommonSliverHeaderDelegate({@required this.islucency,@required this.child,this.backgroundColor});

  @override
  Widget build(BuildContext context, double shrinkOffset, bool overlapsContent) {
    double mainHeight = maxExtent - shrinkOffset;//动态获取滑动剩余高度
    return Container(
      color: backgroundColor??Colors.white,
      child: Opacity(
          opacity:islucency==true&&mainHeight!=maxExtent?((mainHeight / maxExtent)*0.5).clamp(0, 1):1,//根据滑动高度隐藏显示
          child: child
      ),
    );
  }

  @override
  // TODO: implement maxExtent
  double get maxExtent => this.child.preferredSize.height;

  @override
  // TODO: implement minExtent
  double get minExtent => this.child.preferredSize.height;

  @override
  bool shouldRebuild(covariant SliverPersistentHeaderDelegate oldDelegate) {
    // TODO: implement shouldRebuild
    return true;
  }

}

 

好,具体的使用:

代码可能有点乱,大家看重点就行。

首先是NestedScrollView组件,然后就直接添加SliverPersistentHeader组件,在组件中的delegate属性中加入咱们自定义的组件CommonSliverHeaderDelegate。

 

return SafeArea(
      child: NestedScrollView(
        headerSliverBuilder: (BuildContext context, bool innerBoxIsScrolled) {
          return <Widget>[

            SliverPersistentHeader(
                delegate: CommonSliverHeaderDelegate(
                    islucency: true,//需要淡入淡出
                    child:PreferredSize(//这里传入PreferredSize组件,必须是这个,因为咱们自定义中接收到就是这个。
                      preferredSize: Size.fromHeight(60),//定义组件高度,必须写。
                      child: Row(//自由发挥
                        children: [
                          Container(
                            padding: EdgeInsets.all(20),
                            alignment: Alignment.center,
                            child: Text('sdfsdf'),
                          ),
                          Container(
                            padding: EdgeInsets.all(20),
                            alignment: Alignment.center,
                            child: Text('sdfsdf'),
                          ),
                          Container(
                            padding: EdgeInsets.all(20),
                            alignment: Alignment.center,
                            child: Icon(Icons.add),
                          ),
                        ],
                      )
                    )
                )),
            SliverPersistentHeader(
                floating: true,
                pinned: true,
                delegate: CommonSliverHeaderDelegate(
                    islucency: false,
                    child:PreferredSize(
                      preferredSize: Size(double.infinity,48),
                      child:Container(
                        child: TabBar(
                          controller: this._tabController,
                          tabs: <Widget>[
                            Tab(text: '资讯'),
                            Tab(text: '技术'),
                          ],
                        ),
                      )
                    )
                )),
            // SliverAppBar(
            //     pinned: true,
            //     floating: true,
            //     bottom: PreferredSize(
            //       preferredSize: Size(double.infinity,48),
            //       child:TabBar(
            //         indicatorPadding: EdgeInsets.all(10),
            //         labelColor: Colors.black,
            //         controller: this._tabController,
            //         tabs: <Widget>[
            //           Tab(text: '资讯'),
            //           Tab(text: '技术'),
            //         ],
            //       ),
            //     )
            // ),
            SliverGrid(
              gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
                  crossAxisCount: 3, crossAxisSpacing: 5, mainAxisSpacing: 3),
              delegate:
                  SliverChildBuilderDelegate((BuildContext context, int index) {
                return Container(
                  color: Colors.primaries[index % Colors.primaries.length],
                );
              }, childCount: 20),
            )
          ];
        },
        body: TabBarView(
          controller: _tabController, //tabbar控制器
          children: <Widget>[
            Scaffold(
              body: Text('sdf'),
            ),
            Text('sdf'),
          ],
        ),
      ),
    );

上效果:

 

此功能到此为止。接下来我会研究tabbar的自定义高度问题,希望大家有什么问题可以和我探讨。

 

SliverAppBar
posted @ 2021-02-01 19:22  淡然吖  阅读(3980)  评论(0编辑  收藏  举报