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

2024-05-23  本文已影响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;
  }
}
上一篇下一篇

猜你喜欢

热点阅读