如何在Flutter中自定义SliverAppBar中的flexibleSpace属性?

9

我想在SliverAppBar的flexibleSpace属性中使用自定义小部件树,当展开时,在滚动时我想显示自定义文本而不是小部件树。

我已经创建了一个自定义的小部件树,它将被分配给flexibleSpace属性,但我不知道如何在滚动时显示自定义文本并隐藏小部件树。

SliverAppBar(
          expandedHeight: 180.0,
          backgroundColor: const Color(0xFF9e0118),
          iconTheme: IconThemeData(color: Colors.white),
          floating: true,
          pinned: true,
          flexibleSpace: Column(
            mainAxisAlignment: MainAxisAlignment.center,
            crossAxisAlignment: CrossAxisAlignment.center,
            children: <Widget>[
              Container(
                  margin: EdgeInsets.only(top: 16.0),
                  padding: EdgeInsets.only(left: 32.0, right: 32.0),
                  child: Text(
                    'Some text',
                    textAlign: TextAlign.center,
                    style: TextStyle(
                        color: Colors.white,
                        fontFamily: 'PlayfairDisplay',
                        fontStyle: FontStyle.italic,
                        fontSize: 16.0),
                  )),
              Container(
                  margin: EdgeInsets.only(top: 16.0),
                  padding: EdgeInsets.only(left: 32.0, right: 32.0),
                  child: Text(
                    'some text',
                    textAlign: TextAlign.center,
                    style: TextStyle(
                        color: Colors.white,
                        fontFamily: 'PlayfairDisplay',
                        fontSize: 16.0),
                  )),
            ],
          ),
        ),
2个回答

15

你可能想将小部件树包装在FlexibleSpaceBar小部件内,并将小部件树添加为背景。我希望我理解了你的问题。请查看这个gif

SliverAppBar(
      expandedHeight: 180.0,
      backgroundColor: const Color(0xFF9e0118),
      iconTheme: IconThemeData(color: Colors.white),
      floating: true,
      pinned: true,
      flexibleSpace: FlexibleSpaceBar(
        collapseMode: CollapseMode.pin,
        centerTitle: true,
        background: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          crossAxisAlignment: CrossAxisAlignment.center,
          children: <Widget>[
            Container(
                margin: EdgeInsets.only(top: 16.0),
                padding: EdgeInsets.only(left: 32.0, right: 32.0),
                child: Text(
                  'Some text',
                  textAlign: TextAlign.center,
                  style: TextStyle(
                      color: Colors.white,
                      fontFamily: 'PlayfairDisplay',
                      fontStyle: FontStyle.italic,
                      fontSize: 16.0),
                )),
            Container(
                margin: EdgeInsets.only(top: 16.0),
                padding: EdgeInsets.only(left: 32.0, right: 32.0),
                child: Text(
                  'some text',
                  textAlign: TextAlign.center,
                  style: TextStyle(
                      color: Colors.white,
                      fontFamily: 'PlayfairDisplay',
                      fontSize: 16.0),
                )),
          ],
        ),
      ),
    ),

谢谢。这解决了我问题的一部分,即我可以在滚动时隐藏我的自定义小部件树。第二部分是,我还想能够在应用程序栏上显示一些文本,同时固定它,并且用户正在滚动,目前,它只是带有红色背景的空白。 - Ayush Shekhar
嘿,我刚看到你的评论。如果问题还没有解决,让我想一想并给你答案。 - westdabestdb
当然,请做吧。谢谢。 - Ayush Shekhar

6
为了补充@westdabestdb的回答,让标题在滚动时出现,非常简单。您只需添加所选的Animated Widget,并使用滚动控制器的addListener来切换布尔值。要查找更多Animated Widgets,请转到Flutter Animated Widgets的官方文档:https://flutter.dev/docs/development/ui/widgets/animation 这是一个示例,其中包含AnimatedOpacity Widget和Parallax折叠模式,我认为它们很好地配合在一起。
class YourPage extends StatelessWidget {
  const YourPage({Key key}) : super(key: key);

  ScrollController _scrollController;
  bool _isScrolled = false;

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

  @override
  Widget build(BuildContext context) {
    return SafeArea(
      child: Scaffold(
        body: CustomScrollView(
          controller: _scrollController,
          slivers: <Widget>[
            SliverAppBar(
              expandedHeight: 144.0,
              pinned: true,
              forceElevated: true,
              ////////////////////////////////////
              // HERE IS THE PART TO BE ADDED
              title: AnimatedOpacity(
                duration: Duration(milliseconds: 300),
                opacity: _isScrolled ? 1.0 : 0.0,
                curve: Curves.ease,
                child: Text("YOUR TITLE HERE"),
              ),
              ////////////////////////////////////
              flexibleSpace: FlexibleSpaceBar(
                titlePadding: const EdgeInsets.only(bottom: 8.0),
                centerTitle: true,
                collapseMode: CollapseMode.parallax,
                background: Column(
                  mainAxisAlignment: MainAxisAlignment.center,
                  crossAxisAlignment: CrossAxisAlignment.center,
                  children: <Widget>[
                    Container(
                        margin: EdgeInsets.only(top: 16.0),
                        padding: EdgeInsets.only(left: 32.0, right: 32.0),
                        child: Text(
                          'Some text',
                          textAlign: TextAlign.center,
                          style: TextStyle(
                              color: Colors.white,
                              fontFamily: 'PlayfairDisplay',
                              fontStyle: FontStyle.italic,
                              fontSize: 16.0),
                        )),
                    Container(
                        margin: EdgeInsets.only(top: 16.0),
                        padding: EdgeInsets.only(left: 32.0, right: 32.0),
                        child: Text(
                          'some text',
                          textAlign: TextAlign.center,
                          style: TextStyle(
                              color: Colors.white,
                              fontFamily: 'PlayfairDisplay',
                              fontSize: 16.0),
                        )),
                  ],
                ),
              ),
            )
          ],
        ),
      ),
    );
  }

// METHODS
  void _listenToScrollChange() {
    if (_scrollController.offset >= 48.0) {
      setState(() {
        _isScrolled = true;
      });
    } else {
      setState(() {
        _isScrolled = false;
      });
    }
  }
}

你只需要在_listenToScrollChange中玩弄if的值和动画的持续时间,就可以获得所需的输出。

我有一个类似的问题,当我尝试这个答案时,我确实得到了期望的输出,但应用程序的用户界面变得非常卡顿和缓慢。响应时间迅速下降。有没有解决方法? - Nithin Sai
这种方法会过于频繁地在整个小部件树上调用setState(),这肯定会使用户界面变得缓慢。 - Akash Gorai
1
是的,那很可能是对的,我自己没有试过。为了解决问题,你可以检查是否应该更改_isScrolled,从而减少setStates的数量。只需将if更改为这个=> if(_scrollController.offset >= 48.0 && !_isScrolled),以及else if(_isScrolled)。 - Migalv

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接