美文网首页flutter
Flutte--滑动监听总结+应用(appBar滑动渐变)

Flutte--滑动监听总结+应用(appBar滑动渐变)

作者: 鹿蜀先生191 | 来源:发表于2020-11-12 19:31 被阅读0次
    一、滑动监听

    在flutter 中滑动监听的一般实现方式有两种:分别是ScrollerController和NotificationListener。

    二、ScrollerController

    ScrollerController的常用属性和方法

    • offset : 可滚动组件的当前的滑动偏移量;
    • jumpTo(double offset)跳转到指定位置;
    • animateTo(double offset,@required Duration duration,@required Curve curve) 动画式跳转到指定位置;
    三、NotificationListener(通知冒泡)

    Flutter中子组件与父组件之间的通信可以通过发送通知来完成(Notification,父组件通过NotificationListener组件来监听自己关注的通知,这一方式就是通知冒泡。
    NotificationListener常用的属性和方法:

    • onNotification 通知处理回调,返回值类型为bool型,返回值为true时会组织冒泡,父级将再也收不到该通知;返回值为false时继续向上冒泡通知。
    四、两者区别

    首先这两种方式都可以实现对滚动的监听,但是他们还是有一些区别:

    • ScrollController可以控制滚动控件的滚动,而NotificationListener是不可以的。
    • 通过NotificationListener可以在从可滚动组件到widget树根之间任意位置都能监听,而ScrollController只能和具体的可滚动组件关联后才可以。
    • 收到滚动事件后获得的信息不同;NotificationListener在收到滚动事件时,通知中会携带当前滚动位置和ViewPort的一些信息,而ScrollController只能获取当前滚动位置。
    五、应用(实现AppBar滑动渐变)

    以NotificationListener为例,整体思路是:监听页面滑动距离,使用透明度组件覆盖在appbar之上,使之透明度随滑动距离等比例增大,从而实现滑动渐变效果。封装后的组件代码如下:

    const APPBAR_SCROLL_OFFSET = 100;
    
    class SlideGradientAppBar extends StatefulWidget {
      final Widget body;  //滑动主体
      final String title;    //主标题
      final bool isTabTitle;  //是否为tabbar
      final List<String> tabTitles;  //tabbar标题列表
      final TabController tabController;  //tabbar的controller列表
    
      SlideGradientAppBar(
          {this.body,
          this.title,
          this.isTabTitle = false,
          this.tabTitles,
          this.tabController});
    
      @override
      State<StatefulWidget> createState() {
        return _SlideGradientAppBar();
      }
    }
    
    class _SlideGradientAppBar extends State<SlideGradientAppBar> {
      double appBarAlpha = 0;      //appbar透明度
    
    //滑动渐变透明度变化算法
      _onScroll(offset) {
        double alpha = offset / APPBAR_SCROLL_OFFSET;
        if (alpha < 0) {
          alpha = 0;
        } else if (alpha > 1) {
          alpha = 1;
        }
        setState(() {
          appBarAlpha = alpha;
        });
      }
    
      @override
      Widget build(BuildContext context) {
        return Scaffold(
          body: Stack(
            children: [
              StatusBar(
                child: Container(
                  height: 0,
                ),
                brightness: appBarAlpha == 0 ? Brightness.light : Brightness.dark,
              ),
              NotificationListener(
                  // ignore: missing_return
                  onNotification: (scrollNotification) {
                    if (scrollNotification is ScrollUpdateNotification &&
                        scrollNotification.depth == 0) {
                      _onScroll(scrollNotification.metrics.pixels);
                    }
                  },
                  child: widget.body),
              Opacity(
                opacity: appBarAlpha,
                child: Container(
                  width: screenWidth,
                  height: statusBarHeight + 40.px,
                  decoration:
                      BoxDecoration(color: Colors.white, boxShadow: <BoxShadow>[
                    new BoxShadow(
                      color: const Color(0xffE5E9F0),
                      offset: new Offset(0.0, 1.0),
                      blurRadius: 16.0,
                    ),
                  ]),
                ),
              ),
              Container(
                height: 40.px,
                margin: EdgeInsets.only(top: statusBarHeight),
                child: Row(
                  mainAxisAlignment: widget.isTabTitle?MainAxisAlignment.start:MainAxisAlignment.spaceBetween,
                  crossAxisAlignment: CrossAxisAlignment.center,
                  children: <Widget>[
                    GestureDetector(
                        behavior: HitTestBehavior.opaque,
                        onTap: () {
                          Navigator.of(context).pop();
                        },
                        child: Container(
                          padding: EdgeInsets.symmetric(
                              horizontal: 15.px, vertical: 10.px),
                          child: Image(
                            image: AssetImage(
                              appBarAlpha == 0
                                  ? AssetConstant.back_white_2x
                                  : AssetConstant.back_black_2x,
                            ),
                            width: 10.px,
                            height: 18.px,
                          ),
                        )),
                    widget.isTabTitle
                        ? Container(
                            width: 80.px*widget.tabTitles.length,
                            alignment: Alignment.centerLeft,
                            child: TabBar(
                                labelPadding: EdgeInsets.symmetric(horizontal: 0),
                                indicator: const BoxDecoration(),
                                labelColor: Colors.white,
                                unselectedLabelColor: Color(0xFF8EBFFF),
                                labelStyle: TextStyle(fontSize: 18.px),
                                unselectedLabelStyle: TextStyle(fontSize: 15.px),
                                controller: widget.tabController,
                                tabs: widget.tabTitles
                                    .map((e) => Text(
                                          e,
                                          style: TextStyle(
                                              decoration: TextDecoration.none,
                                              fontWeight: FontWeight.w600,
                                              color: appBarAlpha == 0
                                                  ? Colors.white
                                                  : Color(0xff333333)),
                                        ))
                                    .toList()),
                          )
                        : Expanded(
                            child: Container(
                              alignment: Alignment.center,
                              child: Text(
                                widget.title,
                                style: TextStyle(
                                    decoration: TextDecoration.none,
                                    fontSize: 18.px,
                                    fontWeight: FontWeight.w600,
                                    color: appBarAlpha == 0
                                        ? Colors.white
                                        : Color(0xff333333)),
                              ),
                            ),
                          ),
                    Container(
                      width: 40.px,
                    )
                  ],
                ),
              ),
            ],
          ),
        );
      }
    }
    

    使用时调用组件即可,例如:

      @override
      Widget build(BuildContext context) {
        return SlideGradientAppBar(
          body:  widget //主页面组件
          title: "审批详情",);
        ),
      }
    

    实现效果为:


    appbar 滑动渐变.gif

    相关文章

      网友评论

        本文标题:Flutte--滑动监听总结+应用(appBar滑动渐变)

        本文链接:https://www.haomeiwen.com/subject/uayrbktx.html