Flutter实现列表初始在AppBar下方、滚动时滑至其下方的效果
Solution: Scrollable List Under Blurred AppBar
Key Issues in Your Original Code
extendBodyBehindAppBar: trueforces 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
- Scroll Tracking: The
ScrollControllerlistens to scroll events to update_scrollOffset, which drives both the body padding and blur intensity. - Initial Layout:
bodyTopPaddingstarts 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. - Blur Effect:
BackdropFilterapplies 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. - 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
相关产品推荐
相关产品推荐

