SliverHeader行为管理
SliverHeader behaviour management
我的 flutter 应用有 NestedScrollView
和 headerSliverBuilder
。
我的 SliverAppBar
在这个构建器中是这样的:
SliverAppBar(
elevation: 0,
snap: true,
pinned: false,
floating: true,
forceElevated: false,
primary: false,
automaticallyImplyLeading: false,
backgroundColor: Colors.white,
expandedHeight: 65.0 + 75,
flexibleSpace: Container(
child: Column(children: <Widget>[
MyTabBar(true, 65, () {}, () {}),
Container(height: 75, color: Colors.orange)
]),
decoration: BoxDecoration(boxShadow: [
BoxShadow(
color: Colors.black26,
blurRadius: 4.0,
spreadRadius: .0,
),
], color: Colors.white),
)
)
现在,滚动时的行为有点奇怪。我希望它滚动整个 SliverAppBar,包括 flexibleSpace
中的所有内容。但这就是发生的事情:
它滚动到我 header 的橙色部分下方,然后滚动到上方的 tab-part。 tab-part 消失的那一刻,橙色部分也消失了。呵呵..
当我从向下滚动中恢复栏时也是如此。然后橙色的部分就出现在原地,上面的部分滑进去,我想全部滑进去。
自从上次 flutter 更新以来,我的整个行为都发生了变化。
有谁知道我需要做些什么来实现我的预期行为?
这是这个简单示例的完整代码:https://github.com/nietsmmar/SliverHeaderTest/tree/master/flutter_app
如何在 Stack
小部件中使用 AnimatedContainer
?
像这样...
import 'package:flutter/material.dart';
import 'package:vector_math/vector_math_64.dart' hide Colors;
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
final ScrollController scrollController = ScrollController();
return MaterialApp(
theme: ThemeData(
primaryColor: Colors.blue,
),
home: Scaffold(
body: Stack(
children: <Widget>[
SafeArea(
child: ListView(
controller: scrollController,
padding: const EdgeInsets.only(top: 100),
children: List.generate(
100,
(index) => ListTile(
title: Text('This is item #$index'),
),
),
),
),
AnimatedAppBar(
scrollController: scrollController,
child: PreferredSize(
preferredSize: Size.fromHeight(100),
child: const Center(child: Text('APP BAR')),
),
),
],
),
),
);
}
}
class AnimatedAppBar extends StatefulWidget {
AnimatedAppBar({
required this.scrollController,
this.child,
this.toolbarHeight,
});
final ScrollController scrollController;
final PreferredSize? child;
final double? toolbarHeight;
@override
_AnimatedAppBarState createState() => _AnimatedAppBarState();
}
class _AnimatedAppBarState extends State<AnimatedAppBar> {
late double _totalHeight;
late double _lastPosition;
late bool _isShown;
@override
void initState() {
super.initState();
_totalHeight = widget.toolbarHeight ??
kToolbarHeight + (widget.child?.preferredSize.height ?? 0.0);
_lastPosition = widget.scrollController.offset;
_isShown = true;
widget.scrollController.addListener(_scrollListener);
}
void _scrollListener() {
if (_isShown && _lastPosition < widget.scrollController.offset) {
setState(() => _isShown = false);
} else if (!_isShown && _lastPosition > widget.scrollController.offset) {
setState(() => _isShown = true);
}
_lastPosition = widget.scrollController.offset;
}
@override
Widget build(BuildContext context) {
return AnimatedContainer(
width: double.infinity,
height: _totalHeight,
padding: EdgeInsets.only(top: kToolbarHeight),
duration: const Duration(milliseconds: 250),
curve: Curves.easeIn,
transform: Matrix4.translation(
Vector3(0, _isShown ? 0 : -_totalHeight, 0),
),
color: Theme.of(context).primaryColor,
child: widget.child,
);
}
@override
void dispose() {
widget.scrollController.removeListener(_scrollListener);
super.dispose();
}
}
我的 flutter 应用有 NestedScrollView
和 headerSliverBuilder
。
我的 SliverAppBar
在这个构建器中是这样的:
SliverAppBar(
elevation: 0,
snap: true,
pinned: false,
floating: true,
forceElevated: false,
primary: false,
automaticallyImplyLeading: false,
backgroundColor: Colors.white,
expandedHeight: 65.0 + 75,
flexibleSpace: Container(
child: Column(children: <Widget>[
MyTabBar(true, 65, () {}, () {}),
Container(height: 75, color: Colors.orange)
]),
decoration: BoxDecoration(boxShadow: [
BoxShadow(
color: Colors.black26,
blurRadius: 4.0,
spreadRadius: .0,
),
], color: Colors.white),
)
)
现在,滚动时的行为有点奇怪。我希望它滚动整个 SliverAppBar,包括 flexibleSpace
中的所有内容。但这就是发生的事情:
它滚动到我 header 的橙色部分下方,然后滚动到上方的 tab-part。 tab-part 消失的那一刻,橙色部分也消失了。呵呵..
当我从向下滚动中恢复栏时也是如此。然后橙色的部分就出现在原地,上面的部分滑进去,我想全部滑进去。
自从上次 flutter 更新以来,我的整个行为都发生了变化。
有谁知道我需要做些什么来实现我的预期行为?
这是这个简单示例的完整代码:https://github.com/nietsmmar/SliverHeaderTest/tree/master/flutter_app
如何在 Stack
小部件中使用 AnimatedContainer
?
像这样...
import 'package:flutter/material.dart';
import 'package:vector_math/vector_math_64.dart' hide Colors;
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
final ScrollController scrollController = ScrollController();
return MaterialApp(
theme: ThemeData(
primaryColor: Colors.blue,
),
home: Scaffold(
body: Stack(
children: <Widget>[
SafeArea(
child: ListView(
controller: scrollController,
padding: const EdgeInsets.only(top: 100),
children: List.generate(
100,
(index) => ListTile(
title: Text('This is item #$index'),
),
),
),
),
AnimatedAppBar(
scrollController: scrollController,
child: PreferredSize(
preferredSize: Size.fromHeight(100),
child: const Center(child: Text('APP BAR')),
),
),
],
),
),
);
}
}
class AnimatedAppBar extends StatefulWidget {
AnimatedAppBar({
required this.scrollController,
this.child,
this.toolbarHeight,
});
final ScrollController scrollController;
final PreferredSize? child;
final double? toolbarHeight;
@override
_AnimatedAppBarState createState() => _AnimatedAppBarState();
}
class _AnimatedAppBarState extends State<AnimatedAppBar> {
late double _totalHeight;
late double _lastPosition;
late bool _isShown;
@override
void initState() {
super.initState();
_totalHeight = widget.toolbarHeight ??
kToolbarHeight + (widget.child?.preferredSize.height ?? 0.0);
_lastPosition = widget.scrollController.offset;
_isShown = true;
widget.scrollController.addListener(_scrollListener);
}
void _scrollListener() {
if (_isShown && _lastPosition < widget.scrollController.offset) {
setState(() => _isShown = false);
} else if (!_isShown && _lastPosition > widget.scrollController.offset) {
setState(() => _isShown = true);
}
_lastPosition = widget.scrollController.offset;
}
@override
Widget build(BuildContext context) {
return AnimatedContainer(
width: double.infinity,
height: _totalHeight,
padding: EdgeInsets.only(top: kToolbarHeight),
duration: const Duration(milliseconds: 250),
curve: Curves.easeIn,
transform: Matrix4.translation(
Vector3(0, _isShown ? 0 : -_totalHeight, 0),
),
color: Theme.of(context).primaryColor,
child: widget.child,
);
}
@override
void dispose() {
widget.scrollController.removeListener(_scrollListener);
super.dispose();
}
}