Flutter:FlexibleSpaceBar折叠时更改文本

Posted

技术标签:

【中文标题】Flutter:FlexibleSpaceBar折叠时更改文本【英文标题】:Flutter: Change text when FlexibleSpaceBar is collapsed 【发布时间】: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

【问题讨论】:

【参考方案1】:

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

【讨论】:

您也可以查看此问题了解更多详细信息。 ***.com/questions/49942791/…【参考方案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://***.com/a/53380630/9719695

【讨论】:

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

跟进 Vishnu Suresh 的回答:

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

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

【讨论】:

以上是关于Flutter:FlexibleSpaceBar折叠时更改文本的主要内容,如果未能解决你的问题,请参考以下文章

如何修改 Sliverappbar 以便在向上滚动时可以看到带有 FlexibleSpaceBar 的背景图像?

Flutter自定义折线图并添加点击事件

Flutter图表库fl_chart的使用解析(二)-折线图

Flutter 布局类组件:流式布局(Wrap和Flow)

如何在CollapsingToolbar中使用Map的点击事件

flutter中流式布局