Flutter:页面滚动,导航栏背景颜色过渡动画

发布于:2025-03-21 ⋅ 阅读:(25) ⋅ 点赞:(0)

记录:导航默认透明,页面发生滚动后,导航背景色由0-1,过渡到白色背景。
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

view

import 'package:ducafe_ui_core/ducafe_ui_core.dart';
import 'package:flutter/material.dart';
import 'package:get/get.dart';
import 'package:redone/common/index.dart';
import 'package:tdesign_flutter/tdesign_flutter.dart';
import 'index.dart';

class SendRedPacketReceivePage extends GetView<SendRedPacketReceiveController> {
  const SendRedPacketReceivePage({super.key});

  // 头部
  Widget _buildHeader() {
    return <Widget>[
      TDImage(assetUrl: 'assets/chat/images/6.png', width: 750.w, height: 216.w,type: TDImageType.square,),
      <Widget>[
        SizedBox(height: 150.w,),
        TDImage(assetUrl: 'assets/chat/images/user.png', width: 130.w, height: 130.w,type: TDImageType.circle,),
        SizedBox(height: 20.w,),
        TextWidget.body('黄玲玲发出的红包', size: 32.sp, color: AppTheme.color333,weight: FontWeight.w600,),
        SizedBox(height: 10.w,),
        TextWidget.body('恭喜发财,大吉大利', size: 26.sp, color: AppTheme.color999,),
        SizedBox(height: 10.w,),
        <Widget>[
          TextWidget.body('8.88', size: 80.sp, color: AppTheme.primary,weight: FontWeight.w600,),
          SizedBox(width: 10.w,),
          TextWidget.body('元', size: 26.sp, color: AppTheme.primary,weight: FontWeight.w600,),
        ].toRow(mainAxisAlignment: MainAxisAlignment.center,crossAxisAlignment: CrossAxisAlignment.baseline,textBaseline: TextBaseline.alphabetic),
      ].toColumn()
    ].toStack();
  }

  // 红包总数
  Widget _buildRedPacketCount() {
    return <Widget>[
      TextWidget.body('共10个红包,5秒钟抢完', size: 26.sp, color: AppTheme.color999,),
    ].toRow()
    .paddingHorizontal(30.w)
    .height(68.w).backgroundColor(const Color(0xfff3f4f5))
    .clipRRect(all: 10.w);
  }

  // 红包列表
  Widget _buildRedPacketList() {
    return SliverList(
      delegate: SliverChildBuilderDelegate(
        (BuildContext context, int index) {
          return <Widget>[
            TDImage(assetUrl: 'assets/chat/images/user.png',width: 84.w,height: 84.w, type: TDImageType.circle,),
            SizedBox(width: 20.w),
            <Widget>[
              TextWidget.body('黄玲玲', size: 30.sp,color: AppTheme.color333,),
              SizedBox(height: 10.w),
              TextWidget.body('2024-01-01 12:00',size: 24.sp,color: AppTheme.color999,),
            ].toColumn(crossAxisAlignment: CrossAxisAlignment.start,)
            .expanded(),
            TextWidget.body('0.88元',size: 30.sp,color: AppTheme.color333,),
          ].toRow(crossAxisAlignment: CrossAxisAlignment.start)
          .paddingVertical(20.w)
          .decorated(border: const Border(bottom: BorderSide(width: 1, color: AppTheme.dividerColor),));
        },
        childCount: 15,
      ),
    );
  }

  // 主视图
  Widget _buildView() {
    return CustomScrollView(
      controller: controller.scrollController,
      slivers: [
        _buildHeader().sliverToBoxAdapter(),
        SizedBox(height: 60.w,).sliverToBoxAdapter(),
        _buildRedPacketCount().sliverToBoxAdapter().sliverPaddingHorizontal(30.w),
        SizedBox(height: 20.w,).sliverToBoxAdapter(),
        _buildRedPacketList().sliverPaddingHorizontal(30.w),
      ],
    );
  }

  @override
  Widget build(BuildContext context) {
    return GetBuilder<SendRedPacketReceiveController>(
      init: SendRedPacketReceiveController(),
      id: "send_red_packet_receive",
      builder: (_) {
        return Scaffold(
          backgroundColor: AppTheme.pageBgColor,
          body: <Widget>[
            _buildView(),
            AnimatedContainer(
              duration: const Duration(milliseconds: 100),
              color: Colors.white.withOpacity(controller.opacity),
              child: TDNavBar(
                height: 44,
                title: '领取红包',
                titleColor: AppTheme.color333.withOpacity(controller.opacity),
                titleFontWeight: FontWeight.w600,
                backgroundColor: Colors.transparent,
                screenAdaptation: true,
                useDefaultBack: true,
              ),
            ).positioned(left: 0, right: 0, top: 0),
          ].toStack()
        );
      },
    );
  }
}

controller

import 'package:get/get.dart';
import 'package:flutter/material.dart';

class SendRedPacketReceiveController extends GetxController {
  SendRedPacketReceiveController();

  // 滚动控制器
  final ScrollController scrollController = ScrollController();
  
  // 渐变系数 0-1
  double opacity = 0.0;
  
  // 滚动开始变化的位置
  final double scrollStartPoint = 20.0;
  
  // 滚动结束变化的位置
  final double scrollEndPoint = 120.0;

  _initData() {
    update(["send_red_packet_receive"]);
  }


  @override
  void onInit() {
    super.onInit();
    // 监听滚动
    scrollController.addListener(() {
      // 计算 0-1 之间的渐变系数
      double newOpacity;
      
      if (scrollController.offset <= scrollStartPoint) {
        // 开始点之前完全透明
        newOpacity = 0.0;
      } else if (scrollController.offset >= scrollEndPoint) {
        // 结束点之后完全不透明
        newOpacity = 1.0;
      } else {
        // 在开始点和结束点之间线性计算
        newOpacity = (scrollController.offset - scrollStartPoint) /  (scrollEndPoint - scrollStartPoint);
        
        // 确保值在0-1范围内并保留更多小数位精度
        newOpacity = double.parse(newOpacity.toStringAsFixed(3)).clamp(0.0, 1.0);
      }
      
      // 只有当透明度变化时才更新UI
      if ((opacity - newOpacity).abs() > 0.001) {
        opacity = newOpacity;
        update(["send_red_packet_receive"]);
      }
    });
    _initData();
  }

  @override
  void onReady() {
    super.onReady();
    _initData();
  }

  @override
  void onClose() {
    scrollController.dispose();
    super.onClose();
  }
}