如何在Flutter中根据AppBar内容动态更改运行时的AppBar高度?

11

我正在尝试将flutter_tagging实现在AppBar中。我使用下面的代码成功地将标记的TextField添加到了AppBar中,并使用PreferredSize小部件来调整AppBar的大小:

return PreferredSize(
    preferredSize: Size.fromHeight(110),
    child: AppBar(
      backgroundColor: HexColor('171551'),
      leading: const BackButton(),
      flexibleSpace: Padding(
        padding: const EdgeInsets.only(top: 48.0, left: 10, right: 10),
        child: buildTaggedSearch(),
      ),
      title: Container(),
      actions: _buildActions(),
    ),
  );

这是结果:

输入图像描述

我无法解决的问题是,当用户输入太多标签并且标签移到第二行时会发生什么,如下图所示:

输入图像描述

我对Flutter还不是很熟悉,也许我错过了什么,但我应该如何解决此问题并使AppBar根据标签内容调整大小。我查看了大部分在这里谈论AppBar调整大小的问题,它们都使用我在这里使用的PreferredSize小部件。那么,是否还有其他选项?

3个回答

8

运行时没有简单的方法来更改 AppBar 的高度。是的,您可以使用PreferredSize将其设置为任何(固定)高度,但一旦设置,通常不能更改它。

即使您制作自己的类来扩展PreferredSize,它最终也会变成这样:

class CustomAppBar extends StatelessWidget implements PreferredSizeWidget {
  @override
  Size get preferredSize => Size.fromHeight(100); // fixed custom height

  @override
  Widget build(BuildContext context) {...}
}

这个preferredSize的getter需要返回一个固定大小。它的父小部件(Scaffold)真的想知道应用栏高度,以便知道从哪里开始渲染其主体。

如果你将上面的"CustomAppBar"更改为Stateful,你很快就会意识到,你必须重写preferredSize,而它是小部件的一部分而不是状态。

如果你像使用全局变量之类的hack来"欺骗"它:

Size get preferredSize => Size.fromHeight(myAppBarHeight); // global variable

在更改myAppBarHeight的值后,应用栏仍保持在其旧高度。您必须在具有Scaffold的小部件上调用setState才能重绘应用栏,并且更重要的是,在不同位置重绘Scaffold正文。
因此,真正的解决方案可能是在Scaffold级别控制应用栏高度。
或者,您可以查看SliverAppBar
或者不要尝试在运行时更改应用栏高度,例如,使用ListView水平滚动芯片。
或者构建自己的小部件,并且不使用应用栏。

我的 myAppBarHeight 不是全局变量在我身上。 - Burak Mete Erdoğan

1

我在寻找解决方案时,发现可以使用NestedScrollView和插件SliverStickyHeader来解决这个问题。

以下是我的解决方法:

Scaffold(
  body: SafeArea(
    child: NestedScrollView(
      headerSliverBuilder: (BuildContext context, bool innerBoxIsScrolled) {
        return <Widget>[
          SliverStickyHeader(
            sticky: false,
            header: Padding(
              padding: const EdgeInsets.all(8.0),
              child: Column(
                children: [
                  TextField(
                    decoration: InputDecoration(
                        hintText: 'Search', prefixIcon: Icon(Icons.search)),
                  ),
                  Container(
                    height: kToolbarHeight,
                    child: ListView.builder(
                      scrollDirection: Axis.horizontal,
                      itemBuilder: (context, i) {
                        return Center(
                          child: Container(
                            padding: EdgeInsets.all(8.0),
                            margin: EdgeInsets.symmetric(horizontal: 4.0),
                            decoration: BoxDecoration(
                              color: Theme.of(context)
                                  .primaryColor
                                  .withOpacity(0.5),
                              borderRadius: BorderRadius.circular(25.0),
                            ),
                            child: Row(
                              children: [
                                Text(
                                  'Tag $i',
                                  style: TextStyle(
                                    color: Colors.white,
                                  ),
                                ),
                                SizedBox(width: 8.0),
                                CircleAvatar(
                                  radius: 25.0 / 2,
                                  child: Icon(Icons.close),
                                )
                              ],
                            ),
                          ),
                        );
                      },
                    ),
                  ),
                ],
              ),
            ),
          )
        ];
      },
      body: ListView.builder(itemBuilder: (context, i) {
        return ListTile(
          leading: CircleAvatar(child: Text('$i')),
          title: Text('Appbar with dynamic height'),
        );
      }),
    ),
  ),
);

它已经满足了我的需求,插件也完全支持Sliver功能,但我只将其用作标题。希望这对您有所帮助。


0

我曾经遇到过同样的问题,即我想显示搜索和筛选器,但它不会随着正文内容滚动,而是固定在顶部,结果可以滚动。

我没有使用AppBar,而是采用了以下方法:

Scaffold(
  body: Column(
    children: [
      _buildSearchHeader(),
      Expanded(
        child: ListView(
          children: [
              _buildSearchProductResult()
          ],
        ),
      ),
    ],
  )

_buildSearchHeader() 函数中,我声明了我的应用栏内容。
SafeArea(
  child: Container(
    margin: EdgeInsets.fromLTRB(
        homePageMargin, homePageMargin, homePageMargin, 0),
    width: double.infinity,
    child: Column(
      mainAxisAlignment: MainAxisAlignment.spaceBetween,
      children: [
        Align(child: SectionTitle("Search", fontSize: 20),
            alignment: Alignment.centerLeft),
        SizedBox(height: 22),
        _buildSearchBox(), // search bar
        if(showSortSection) _buildSortSection() // sort section/ or any other 
      ],
    ),
  ),
);

现在我能够完美地创建动态出现和滚动选项。

注意:这可能不是最完美的方法。如果有任何开发者知道更好的方法,请在此告诉我。


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