SliverHeader行为管理

SliverHeader behaviour management

我的 flutter 应用有 NestedScrollViewheaderSliverBuilder

我的 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();
  }
}