美文网首页
Flutter根据滑动距离实现导航栏渐变效果

Flutter根据滑动距离实现导航栏渐变效果

作者: 羽辰梦 | 来源:发表于2024-05-23 11:30 被阅读0次
    Untitled.gif
    import 'package:flutter/material.dart';
    import 'dart:math';
    
    class CustomGradationNavigationBar extends StatefulWidget {
      const CustomGradationNavigationBar({super.key});
    
      @override
      State<CustomGradationNavigationBar> createState() =>
          _CustomGradationNavigationBarState();
    }
    
    class _CustomGradationNavigationBarState
        extends State<CustomGradationNavigationBar> {
      double _scrollDistance = 0.0;
      final double _imageShowHeight = 300;
    
      @override
      Widget build(BuildContext context) {
        final navHeight =
            MediaQuery.of(context).padding.top + AppBar().preferredSize.height;
    
        return RefreshIndicator(
          onRefresh: () async {
            return Future.delayed(Duration(seconds: 1), () {
              print("刷新了======");
            });
          },
          child: SizedBox(
            width: double.infinity,
            height: double.infinity,
            child: Stack(
              children: [
                Positioned(
                  left: 0,
                  top: _scrollDistance < 0 ? min(_scrollDistance, 0) : 0,
                  bottom: 0,
                  right: 0,
                  child: Scaffold(
                    body: NotificationListener(
                      onNotification:
                          (ScrollUpdateNotification scrollNotification) {
                        if (scrollNotification.depth == 0) {
                          // print(scrollNotification.metrics.pixels);
                          setState(() {
                            _scrollDistance = scrollNotification.metrics.pixels;
                          });
                        }
                        return false;
                      },
                      child: CustomScrollView(
                        // physics: ClampingScrollPhysics(),
                        slivers: [
                          const SliverToBoxAdapter(),
                          //sliver很奇怪 会把最上面的那个悬浮,所以这里加一个空widgit使图片跟着下拉
                          SliverPersistentHeader(
                            delegate: MyDelegate(
                              //当下拉的时候_scrollDistance为负数 要图片放大 图片高度就是: maxHeight - _scrollDistance
                              //当上划的时候 图片高度不变 直接使用:maxHeight
                              imageShowHeight: _scrollDistance < 0
                                  ? (_imageShowHeight - _scrollDistance)
                                  : _imageShowHeight,
                              imgUrl:
                                  "https://img.zcool.cn/community/01c6615d3ae047a8012187f447cfef.jpg@1280w_1l_2o_100sh.jpg",
                            ),
                          ),
                          SliverList(
                            delegate: SliverChildBuilderDelegate((ctx, index) {
                              return Text("data: $index");
                            }, childCount: 100),
                          )
                        ],
                      ),
                    ),
                  ),
                ),
                CustomNavBar(
                    scrollDistance: _scrollDistance,
                    imageShowHeight: _imageShowHeight),
              ],
            ),
          ),
        );
      }
    }
    
    class CustomNavBar extends StatelessWidget {
      final double scrollDistance;
      final double imageShowHeight;
    
      const CustomNavBar({
        super.key,
        required this.scrollDistance,
        required this.imageShowHeight,
      });
    
      @override
      Widget build(BuildContext context) {
        final navHeight =
            MediaQuery.of(context).padding.top + AppBar().preferredSize.height;
    
        //滚动距离是 0 滑到导航栏的高度, 这边做下渐变  如果距离小于0  那就直接设置透明度为0
        final percent = scrollDistance > 0.0
            ? min(scrollDistance, imageShowHeight - navHeight) /
                (imageShowHeight - navHeight)
            : 0.0;
    
        //print("percent: $percent, distance: $_scrollDistance, height: ${_imageShowHeight - navHeight}");
    
        return SizedBox(
          height: navHeight,
          child: AppBar(
            elevation: 0,
            title: const Text("这里是标题"),
            backgroundColor: Colors.red.withAlpha((percent * 255).toInt()),
          ),
        );
      }
    }
    
    class MyDelegate extends SliverPersistentHeaderDelegate {
      final double imageShowHeight;
      final String imgUrl;
    
      MyDelegate({
        required this.imageShowHeight,
        required this.imgUrl,
      });
    
      @override
      Widget build(
          BuildContext context, double shrinkOffset, bool overlapsContent) {
        return Image.network(
          imgUrl,
          fit: BoxFit.cover,
          height: imageShowHeight,
        );
      }
    
      @override
      double get maxExtent => imageShowHeight;
    
      @override
      double get minExtent => imageShowHeight;
    
      @override
      bool shouldRebuild(SliverPersistentHeaderDelegate oldDelegate) {
        return true;
      }
    }
    

    相关文章

      网友评论

          本文标题:Flutter根据滑动距离实现导航栏渐变效果

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