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

实现Flutter SliverAppBar仿Telegram的滚动行为

实现类似Telegram的SliverAppBar滚动效果(Flutter)

Telegram的SliverAppBar核心滚动行为是:展开时显示完整头部(含头像、居中标题),向下滚动时逐渐折叠,最终固定为紧凑的顶部导航栏(标题左移、头像缩小)。以下是具体实现方案:

基础实现(核心配置)

通过SliverAppBar内置属性快速搭建基础折叠效果:

import 'package:flutter/material.dart';

void main() => runApp(const TelegramStyleApp());

class TelegramStyleApp extends StatelessWidget {
  const TelegramStyleApp({super.key});

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
        body: CustomScrollView(
          slivers: [
            SliverAppBar(
              pinned: true, // 保持AppBar始终固定在顶部
              expandedHeight: 200, // 展开时的总高度
              backgroundColor: const Color(0xFF0088CC), // Telegram主题蓝
              flexibleSpace: FlexibleSpaceBar(
                centerTitle: true,
                titlePadding: const EdgeInsets.only(bottom: 16),
                title: const Text(
                  '联系人',
                  style: TextStyle(color: Colors.white, fontSize: 18),
                ),
                // 展开状态下的头部内容
                background: Padding(
                  padding: const EdgeInsets.only(bottom: 50),
                  child: Center(
                    child: CircleAvatar(
                      radius: 40,
                      backgroundColor: Colors.white,
                      child: Image.network('https://picsum.photos/200'),
                    ),
                  ),
                ),
              ),
            ),
            // 滚动内容列表
            SliverList(
              delegate: SliverChildBuilderDelegate(
                (context, index) => ListTile(
                  leading: const CircleAvatar(child: Icon(Icons.person)),
                  title: Text('联系人 $index'),
                  subtitle: const Text('最近消息'),
                ),
                childCount: 50,
              ),
            ),
          ],
        ),
      ),
    );
  }
}

进阶自定义(精细过渡效果)

要实现Telegram那种标题位置切换、头像大小动态变化的精细效果,可通过LayoutBuilder监听滚动约束,结合状态更新调整组件参数:

import 'package:flutter/material.dart';

void main() => runApp(const TelegramStyleApp());

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

  @override
  State<TelegramStyleApp> createState() => _TelegramStyleAppState();
}

class _TelegramStyleAppState extends State<TelegramStyleApp> {
  double _avatarRadius = 40;

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
        body: CustomScrollView(
          slivers: [
            SliverAppBar(
              pinned: true,
              expandedHeight: 200,
              backgroundColor: const Color(0xFF0088CC),
              // 通过LayoutBuilder获取实时滚动约束
              flexibleSpace: LayoutBuilder(
                builder: (context, constraints) {
                  // 计算折叠比例:0=完全展开,1=完全折叠
                  final scrollOffset = constraints.biggest.height - kToolbarHeight;
                  final collapseRatio = 1 - (scrollOffset / (200 - kToolbarHeight)).clamp(0, 1);

                  setState(() {
                    // 动态调整头像大小:从40缩小到30
                    _avatarRadius = 40 - (collapseRatio * 10);
                  });

                  return Stack(
                    fit: StackFit.expand,
                    children: [
                      // 背景层
                      Container(color: const Color(0xFF0088CC)),
                      // 随滚动缩小的头像
                      Positioned(
                        left: MediaQuery.of(context).size.width / 2 - _avatarRadius,
                        bottom: 50,
                        child: CircleAvatar(
                          radius: _avatarRadius,
                          backgroundColor: Colors.white,
                          child: Image.network('https://picsum.photos/200'),
                        ),
                      ),
                      // 从居中切换到左对齐的标题
                      Positioned(
                        bottom: collapseRatio > 0.5 ? 16 : 0,
                        left: collapseRatio > 0.5 ? null : 16,
                        right: collapseRatio > 0.5 ? 0 : null,
                        child: Opacity(
                          opacity: collapseRatio > 0 ? collapseRatio : 1,
                          child: Text(
                            '联系人',
                            style: const TextStyle(color: Colors.white, fontSize: 18),
                            textAlign: collapseRatio > 0.5 ? TextAlign.center : TextAlign.left,
                          ),
                        ),
                      ),
                    ],
                  );
                },
              ),
            ),
            SliverList(
              delegate: SliverChildBuilderDelegate(
                (context, index) => ListTile(
                  leading: const CircleAvatar(child: Icon(Icons.person)),
                  title: Text('联系人 $index'),
                  subtitle: const Text('最近消息'),
                ),
                childCount: 50,
              ),
            ),
          ],
        ),
      ),
    );
  }
}

关键注意点

  • pinned: true是固定导航栏的核心配置,确保AppBar不会完全滚出屏幕
  • 通过LayoutBuilder获取的constraints.biggest.height可实时获取当前AppBar高度,以此计算折叠比例
  • 动态变化的组件属性需通过setState触发重绘,实现平滑过渡

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.11 05:10:33