【问题标题】:Flutter: Change text when FlexibleSpaceBar is collapsedFlutter:FlexibleSpaceBar折叠时更改文本
【发布时间】:2018-11-27 07:39:02
【问题描述】:

我查看了 Flutter 文档,试图找到一个事件、回调,甚至是当 FlexibleSpaceBar 折叠或展开时我可以挂钩的状态。

return new FlexibleSpaceBar(
  title: new Column(
    crossAxisAlignment: CrossAxisAlignment.end,
    mainAxisAlignment: MainAxisAlignment.end,
    children: <Widget>[
        new Text(_name, style: textTheme.headline),
        new Text(_caption, style: textTheme.caption)
    ]),
  centerTitle: false,
  background: getImage());`

当 FlexibleSpaceBar 卡入(折叠)时,我想隐藏 _caption 文本,只显示 _name 文本。当它完全展开时,我显然想同时显示 _name 和 _caption。

我该怎么做?

我是新来的,所以我对此有些迷茫。

也报告于https://github.com/flutter/flutter/issues/18567

【问题讨论】:

    标签: dart flutter flutter-layout flutter-sliver


    【解决方案1】:

    FlexibleSpaceBar 本身还不够。您需要将其包装成CustomScrollView 和SliverAppBar。这些小部件必须由ScrollController 控制,只要滚动偏移发生变化,就会触发一个事件。根据它,您可以了解应用栏是折叠还是展开,并相应地更改内容。 Here 你会找到一个可行的例子。

    【讨论】:

    【解决方案2】:

    可以这样做:

    在您的 initState 方法中添加这样的滚动侦听器:

      ScrollController _controller;
      bool silverCollapsed = false;
      String myTitle = "default title";
    
      @override
      void initState() {
        super.initState();
    
        _controller = ScrollController();
    
        _controller.addListener(() {
           if (_controller.offset > 220 && !_controller.position.outOfRange) {
              if(!silverCollapsed){
    
                // do what ever you want when silver is collapsing !
    
                myTitle = "silver collapsed !";
                silverCollapsed = true;
                setState(() {});
              }
           }
           if (_controller.offset <= 220 && !_controller.position.outOfRange) {
             if(silverCollapsed){
    
                // do what ever you want when silver is expanding !
    
                myTitle = "silver expanded !";
                silverCollapsed = false;
                setState(() {});
             }
           }
        });
     }
    

    然后将您的 silverAppBar 包裹在 CustomScrollView 中,然后像这样将控制器添加到 CustomScrollView 中:

     @override
     Widget build(BuildContext context) {
        return Scaffold(
           backgroundColor: Colors.white,
           body: CustomScrollView(
              controller: _controller,
              slivers: <Widget>[
                 SliverAppBar(
                    expandedHeight: 300,
                    title: myTitle,
                    flexibleSpace: FlexibleSpaceBar(),
                 ),
                 SliverList(
                    delegate: SliverChildListDelegate(<Widget>[
                       // your widgets inside here !
                    ]),
                 ),
              ],
           ),
        );
    }
    

    最后更改条件值_controller.offset &gt; 220 以满足您的需要!

    【讨论】:

      【解决方案3】:

      在 FlexibleSpaceBar 中指定填充高度

      flexibleSpace: FlexibleSpaceBar(
                titlePadding: EdgeInsets.only(
                  top: 100, // give the value
                title: Text(
                  "Test"
              ),
      

      【讨论】:

        【解决方案4】:

        创建自己的 FlexibleSpaceBar 并不难。

        import 'dart:math' as math;
        
        import 'package:flutter/material.dart';
        import 'package:flutter/rendering.dart';
        
        void main() {
          runApp(MyApp());
        }
        
        class MyApp extends StatelessWidget {
          @override
          Widget build(BuildContext context) {
            return MaterialApp(
              title: 'Flutter Demo',
              theme: ThemeData(
                primarySwatch: Colors.blue,
              ),
              home: Scaffold(
                body: SafeArea(
                  child: MyHomePage(),
                ),
              ),
            );
          }
        }
        
        class MyHomePage extends StatefulWidget {
          @override
          _MyHomePageState createState() => _MyHomePageState();
        }
        
        class _MyHomePageState extends State<MyHomePage> {
          ScrollController controller = ScrollController();
          @override
          Widget build(BuildContext context) {
            return CustomScrollView(
              physics: ClampingScrollPhysics(),
              controller: controller,
              slivers: [
                SliverAppBar(
                  expandedHeight: 220.0,
                  floating: true,
                  pinned: true,
                  elevation: 50,
                  backgroundColor: Colors.pink,
                  leading: IconButton(
                    icon: Icon(Icons.menu),
                    onPressed: () {},
                  ),
                  flexibleSpace: _MyAppSpace(),
                ),
                SliverList(
                  delegate: SliverChildListDelegate(
                    List.generate(
                      200,
                      (index) => Card(
                        child: Padding(
                          padding: EdgeInsets.all(10),
                          child: Text('text $index'),
                        ),
                      ),
                    ),
                  ),
                )
              ],
            );
          }
        }
        
        class _MyAppSpace extends StatelessWidget {
          const _MyAppSpace({Key key}) : super(key: key);
        
          @override
          Widget build(BuildContext context) {
            return LayoutBuilder(
              builder: (context, c) {
                final settings = context
                    .dependOnInheritedWidgetOfExactType<FlexibleSpaceBarSettings>();
                final deltaExtent = settings.maxExtent - settings.minExtent;
                final t =
                    (1.0 - (settings.currentExtent - settings.minExtent) / deltaExtent)
                        .clamp(0.0, 1.0) as double;
                final fadeStart = math.max(0.0, 1.0 - kToolbarHeight / deltaExtent);
                const fadeEnd = 1.0;
                final opacity = 1.0 - Interval(fadeStart, fadeEnd).transform(t);
        
                return Stack(
                  children: [
                    Center(
                      child: Opacity(
                          opacity: 1 - opacity,
                          child: getTitle(
                            'Collapsed Title',
                          )),
                    ),
                    Opacity(
                      opacity: opacity,
                      child: Stack(
                        alignment: Alignment.bottomCenter,
                        children: [
                          getImage(),
                          getTitle(
                            'Expended Title',
                          )
                        ],
                      ),
                    ),
                  ],
                );
              },
            );
          }
        
          Widget getImage() {
            return Container(
              width: double.infinity,
              child: Image.network(
                'https://source.unsplash.com/daily?code',
                fit: BoxFit.cover,
              ),
            );
          }
        
          Widget getTitle(String text) {
            return Padding(
              padding: const EdgeInsets.all(8.0),
              child: Text(
                text,
                textAlign: TextAlign.center,
                style: TextStyle(
                  color: Colors.white,
                  fontSize: 26.0,
                  fontWeight: FontWeight.bold,
                ),
              ),
            );
          }
        }
        

        【讨论】:

          【解决方案5】:

          您可以使用 AnimatedOpacity 类。

           flexibleSpace:  LayoutBuilder(
                              builder: (BuildContext context, BoxConstraints constraints) {
                               var top = constraints.biggest.height;
                                return FlexibleSpaceBar(
                                    title: AnimatedOpacity(
                                        duration: Duration(milliseconds: 300),
                                         //opacity: top > 71 && top < 91 ? 1.0 : 0.0,                           
                                        child: Text(
                                         top > 71 && top < 91 ? "Collapse" : "Expanded",
                                          style: TextStyle(fontSize: 16, fontWeight: FontWeight.bold),
                                        )),
                                    background: Image.network(
                                      "https://images.ctfassets.net/pjshm78m9jt4/383122_header/d79a41045d07d114941f7641c83eea6d/importedImage383122_header",
                                      fit: BoxFit.cover,
                                    ));
                              }),
          
          

          可以从此链接查看原始答案
          https://stackoverflow.com/a/53380630/9719695

          【讨论】:

          • 哇,兄弟,你节省了我的时间
          • 我只会将AnimatedOpacity 包裹在LayoutBuilder 中,以防止图像在每次构建时重新渲染。谢谢;-)
          【解决方案6】:

          跟进 Vishnu Suresh 的回答:

          flexibleSpace: FlexibleSpaceBar(
                titlePadding: EdgeInsets.only(
                  top: kToolbarHeight, // give the value
                title: Text(
                  "Test"
              ),
          

          这将使用 appbar 高度作为填充。

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 2011-08-24
            • 2021-08-09
            • 1970-01-01
            • 2012-02-26
            • 1970-01-01
            • 2017-08-30
            • 2015-06-20
            • 1970-01-01
            相关资源
            最近更新 更多