You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在Flutter中实现带Tween字号动画的吸顶头部及下方吸顶搜索栏

Flutter 带搜索框的渐变字号吸顶头部实现方案

核心思路是通过CustomScrollView组合Sliver组件,监听滚动偏移量动态计算标题字号,同时用固定高度的SliverPersistentHeader实现搜索框吸顶效果,具体实现步骤如下:

  • 配置滚动容器:使用CustomScrollView作为根滚动容器,所有头部、搜索框、列表内容都以Sliver形式作为子组件传入
  • 实现渐变字号的头部:使用SliverAppBar作为头部载体,设置pinned: true保证头部不会完全滚出屏幕,在flexibleSpace的LayoutBuilder中获取当前滚动收缩偏移,计算收缩进度后通过Tween映射标题字号,核心计算逻辑示例:
    // 头部最大展开高度、最小收缩高度
    const double maxHeaderHeight = 120;
    const double minHeaderHeight = kToolbarHeight;
    // 在LayoutBuilder中获取当前收缩偏移
    final currentHeight = constraints.biggest.height;
    final shrinkProgress = ((maxHeaderHeight - currentHeight) / (maxHeaderHeight - minHeaderHeight)).clamp(0.0, 1.0);
    // 计算当前字号:展开时28sp,收缩时18sp
    final titleFontSize = Tween<double>(begin: 28, end: 18).transform(1 - shrinkProgress);
    
  • 实现吸顶搜索框:使用SliverPersistentHeader承载搜索TextField,自定义SliverPersistentHeaderDelegate,将minExtent和maxExtent都设置为搜索框的固定高度(示例为56),同时设置pinned: true,即可保证搜索框滚动到头部下方后始终吸附固定
  • 填充列表内容:下方的列表内容使用SliverList或SliverGrid实现,正常传入子项即可

完整可运行Demo代码如下:

import 'package:flutter/material.dart';

class StickySearchHeaderDemo extends StatefulWidget {
  const StickySearchHeaderDemo({super.key});

  @override
  State<StickySearchHeaderDemo> createState() => _StickySearchHeaderDemoState();
}

class _StickySearchHeaderDemoState extends State<StickySearchHeaderDemo> {
  static const double maxHeaderHeight = 120;
  static const double minHeaderHeight = kToolbarHeight;
  static const double searchBarHeight = 56;

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: CustomScrollView(
        slivers: [
          // 渐变标题头部
          SliverAppBar(
            pinned: true,
            expandedHeight: maxHeaderHeight,
            automaticallyImplyLeading: false,
            flexibleSpace: LayoutBuilder(
              builder: (context, constraints) {
                final currentHeight = constraints.biggest.height;
                final shrinkProgress = ((maxHeaderHeight - currentHeight) / (maxHeaderHeight - minHeaderHeight)).clamp(0.0, 1.0);
                final titleFontSize = Tween<double>(begin: 28, end: 18).transform(1 - shrinkProgress);
                return Padding(
                  padding: EdgeInsets.only(left: 16, bottom: 16, top: MediaQuery.of(context).padding.top + 8),
                  child: Align(
                    alignment: Alignment.bottomLeft,
                    child: Text(
                      "首页",
                      style: TextStyle(fontSize: titleFontSize, fontWeight: FontWeight.bold),
                    ),
                  ),
                );
              },
            ),
          ),
          // 吸顶搜索框
          SliverPersistentHeader(
            pinned: true,
            delegate: _SearchBarDelegate(height: searchBarHeight),
          ),
          // 列表内容
          SliverList.builder(
            itemCount: 50,
            itemBuilder: (context, index) => ListTile(title: Text("列表项 $index")),
          )
        ],
      ),
    );
  }
}

class _SearchBarDelegate extends SliverPersistentHeaderDelegate {
  final double height;

  _SearchBarDelegate({required this.height});

  @override
  Widget build(BuildContext context, double shrinkOffset, bool overlapsContent) {
    return Container(
      height: height,
      color: Theme.of(context).scaffoldBackgroundColor,
      padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 8),
      child: const TextField(
        decoration: InputDecoration(
          hintText: "搜索内容",
          prefixIcon: Icon(Icons.search),
          border: OutlineInputBorder(borderRadius: BorderRadius.all(Radius.circular(8))),
          contentPadding: EdgeInsets.zero
        ),
      ),
    );
  }

  @override
  double get maxExtent => height;

  @override
  double get minExtent => height;

  @override
  bool shouldRebuild(covariant _SearchBarDelegate oldDelegate) {
    return oldDelegate.height != height;
  }
}

内容的提问来源于stack exchange,提问作者Komal

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.24 08:06:03