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

Flutter实现滚动时标题在页面主体与AppBar间的双向过渡

实现滚动时标题在原位置与AppBar间的过渡效果

这种滚动过渡效果可以通过监听滚动偏移量+动态控制组件的透明度/位置来实现,以下是Flutter中的具体实现方案:

核心思路

  1. 准备两个相同的标题组件:一个放在页面内容顶部,一个放在AppBar中
  2. 监听滚动控制器的偏移量,根据滚动距离计算过渡参数(透明度、位置偏移)
  3. 利用Opacity和Transform组件实现平滑的视觉过渡

完整代码示例

import 'package:flutter/material.dart';

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

  @override
  State<TitleScrollTransitionPage> createState() => _TitleScrollTransitionPageState();
}

class _TitleScrollTransitionPageState extends State<TitleScrollTransitionPage> {
  final ScrollController _scrollController = ScrollController();
  double _scrollOffset = 0.0;

  @override
  void initState() {
    super.initState();
    // 监听滚动偏移
    _scrollController.addListener(() {
      setState(() {
        _scrollOffset = _scrollController.offset;
      });
    });
  }

  @override
  void dispose() {
    _scrollController.dispose();
    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    final double appBarHeight = AppBar().preferredSize.height;
    // 过渡阈值:页面标题的高度,可根据实际需求调整
    const double transitionThreshold = 120.0;
    
    // 计算透明度:滚动超过阈值后,AppBar标题完全显示,页面标题完全隐藏
    final double titleOpacity = _scrollOffset > transitionThreshold 
        ? 1.0 
        : _scrollOffset / transitionThreshold;
    // 页面标题的Y轴偏移:滚动超过阈值后,向上移动至AppBar位置
    final double contentTitleYOffset = _scrollOffset > transitionThreshold 
        ? -appBarHeight 
        : 0.0;

    return Scaffold(
      appBar: AppBar(
        title: Opacity(
          opacity: titleOpacity,
          child: const Text("我的页面标题"),
        ),
        // 随滚动逐渐显示AppBar背景色
        backgroundColor: Colors.white.withOpacity(titleOpacity),
        // 随滚动逐渐显示阴影
        elevation: titleOpacity > 0 ? 4 : 0,
      ),
      body: SingleChildScrollView(
        controller: _scrollController,
        child: Column(
          children: [
            // 页面内的标题组件
            Transform.translate(
              offset: Offset(0, contentTitleYOffset),
              child: Opacity(
                opacity: 1 - titleOpacity,
                child: Container(
                  height: transitionThreshold,
                  padding: const EdgeInsets.symmetric(horizontal: 16),
                  alignment: Alignment.centerLeft,
                  child: const Text(
                    "我的页面标题",
                    style: TextStyle(
                      fontSize: 32,
                      fontWeight: FontWeight.bold,
                    ),
                  ),
                ),
              ),
            ),
            // 页面主体内容
            ...List.generate(50, (index) {
              return ListTile(
                title: Text("列表项 $index"),
                leading: const Icon(Icons.list),
              );
            }),
          ],
        ),
      ),
    );
  }
}

关键细节说明

  • 过渡阈值:transitionThreshold设置为页面标题的高度,确保滚动到标题完全移出视图时完成过渡
  • 动画参数:通过titleOpacity同步控制两个标题的透明度,contentTitleYOffset让页面标题平滑移动到AppBar位置
  • AppBar样式过渡:随滚动逐渐显示背景色和阴影,让整体过渡更自然

内容的提问来源于stack exchange,提问作者Gabriel Ángel Canals Salleras

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.01 02:34:53