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

Flutter实现列表初始在AppBar下方、滚动时滑至其下方的效果

Solution: Scrollable List Under Blurred AppBar

Key Issues in Your Original Code

  • extendBodyBehindAppBar: true forces the body to render under the AppBar initially, which contradicts your requirement of the list starting below the AppBar.
  • No scroll tracking or blur effect logic was implemented to adjust the AppBar's appearance as the list scrolls.

Fixed Implementation

Here's a working version that meets both your requirements:

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

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

  @override
  State<YourScreen> createState() => _YourScreenState();
}

class _YourScreenState extends State<YourScreen> {
  late final ScrollController _scrollController;
  double _scrollOffset = 0.0;

  @override
  void initState() {
    super.initState();
    _scrollController = ScrollController();
    _scrollController.addListener(_updateScrollOffset);
  }

  void _updateScrollOffset() {
    setState(() {
      _scrollOffset = _scrollController.offset;
    });
  }

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

  @override
  Widget build(BuildContext context) {
    // Calculate total AppBar height (status bar + toolbar)
    final appBarTotalHeight = MediaQuery.of(context).padding.top + kToolbarHeight;
    // Adjust top padding to keep list below AppBar initially, reduce as user scrolls
    final bodyTopPadding = max(appBarTotalHeight - _scrollOffset, 0.0);
    // Blur intensity increases from 0 to 1 as scroll offset reaches AppBar height
    final blurIntensity = min(_scrollOffset / appBarTotalHeight, 1.0);

    return Scaffold(
      body: Stack(
        children: [
          // Main content: List + Bottom Container
          Padding(
            padding: EdgeInsets.only(top: bodyTopPadding),
            child: Column(
              children: [
                Expanded(
                  child: ListView.separated(
                    controller: _scrollController,
                    padding: const EdgeInsets.all(10),
                    itemCount: sentences.length, // Replace with your actual item count
                    separatorBuilder: (context, index) => const SizedBox(height: 10),
                    itemBuilder: (context, index) {
                      final sentence = sentences.elementAt(index);
                      return ListTile(
                        // Your ListTile content here
                        title: Text(sentence),
                      );
                    },
                  ),
                ),
                Container(
                  color: Colors.red.withAlpha(50),
                  height: 200,
                  child: Row(
                    mainAxisAlignment: MainAxisAlignment.center,
                    children: [
                      FilledButton.icon(
                        label: const Text('this is button'),
                        onPressed: canStartLearning
                            ? () {
                                context
                                    .read<Bloc>()
                                    .add(DoSomething(something.toList()));
                              }
                            : null,
                      ),
                    ],
                  ),
                ),
              ],
            ),
          ),
          // Blurred AppBar (positioned on top)
          Positioned(
            top: 0,
            left: 0,
            right: 0,
            child: Container(
              height: appBarTotalHeight,
              child: AppBar(
                titleSpacing: 24,
                title: const Text('hello world'),
                backgroundColor: Colors.black12.withOpacity(blurIntensity),
                elevation: 0,
                scrolledUnderElevation: 0,
                shape: Border(
                  bottom: BorderSide(
                    color: Colors.black26.withOpacity(blurIntensity),
                  ),
                ),
                // Apply blur effect when scrolling
                flexibleSpace: blurIntensity > 0
                    ? BackdropFilter(
                        filter: ImageFilter.blur(
                          sigmaX: 6 * blurIntensity,
                          sigmaY: 6 * blurIntensity,
                        ),
                        child: Container(color: Colors.transparent),
                      )
                    : null,
              ),
            ),
          ),
        ],
      ),
    );
  }
}

Key Explanations

  1. Scroll Tracking: The ScrollController listens to scroll events to update _scrollOffset, which drives both the body padding and blur intensity.
  2. Initial Layout: bodyTopPadding starts at the full AppBar height, ensuring the list begins below the AppBar. As the user scrolls down, this padding decreases, allowing the list to slide under the AppBar.
  3. Blur Effect: BackdropFilter applies a dynamic blur to the AppBar, with intensity increasing as the list scrolls under it. The opacity of the AppBar's background and border also adjusts to match the blur intensity.
  4. Stack Layout: The AppBar is positioned on top of the main content, ensuring it stays visible while the list scrolls underneath.

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.14 17:52:34