【问题标题】:Flutter: How to automatically update AppBar bottom height depending on child height?Flutter:如何根据孩子身高自动更新AppBar底部高度?
【发布时间】:2020-05-29 12:57:53
【问题描述】:

AppBars 底部属性的类型是PreferredSizeWidget,所以我提供了PreferredSize 小部件,它需要在preferredSize 属性中指定要使用的实际大小。但我不需要静态数字,而是根据孩子自动计算,在我的例子中是 Wrap 小部件。问题是Wrap的高度只有在使用RenderObject调用build方法后才能确定。

我有什么:

我想要的(gif编辑软件制作):

Code in DartPad

代码:

import 'package:flutter/material.dart';

void main() {
  runApp(MyApp());
}

class MyApp extends StatefulWidget {
  _MyAppState createState() => _MyAppState();
}

class _MyAppState extends State<MyApp> {
  final items = List.generate(400, (index) => '$index');
  final filterOptions = <IntType>[];

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
        body: buildBody(),
        appBar: AppBar(
          title: Text('Simple filtering'),
          bottom: buildAppBarBottom(),
        ),
      ),
    );
  }

  Widget buildBody() {
    return Scrollbar(
      child: ListView.builder(
        itemCount: items.length,
        itemBuilder: (context, index) {
          final item = items[index];

          if (filterOptions.every((option) => item.contains(option.symbol))) {
            return ListTile(title: Text(item));
          }

          return Container(height: 0.0001);
        },
      ),
    );
  }

  PreferredSizeWidget buildAppBarBottom() {
    return PreferredSize(
      preferredSize: Size.fromHeight(100),  // change height depending on the child height
      child: Wrap(
        spacing: 8,
        children: IntType.values.map((option) {
          return FilterChip(
            selectedColor: Colors.white,
            selected: filterOptions.contains(option),
            onSelected: (isSelected) {
              setState(() {
                if (isSelected) {
                  filterOptions.add(option);
                } else {
                  filterOptions.remove(option);
                }
              });
            },
            label: Text(option.name),
          );
        }).toList(),
      ),
    );
  }
}

class IntType {
  static const IntType one = const IntType._('One', '1');
  static const IntType two = const IntType._('Two', '2');
  static const IntType three = const IntType._('Three', '3');
  static const IntType four = const IntType._('Four', '4');
  static const IntType five = const IntType._('Five', '5');
  static const IntType six = const IntType._('Six', '6');
  static const IntType seven = const IntType._('Seven', '7');
  static const IntType eight = const IntType._('Eight', '8');
  static const IntType nine = const IntType._('Nine', '9');
  static const IntType zero = const IntType._('Zero', '0');

  final String name;
  final String symbol;

  const IntType._(this.name, this.symbol);

  static const values = [
    IntType.one,
    IntType.two,
    IntType.three,
    IntType.four,
    IntType.five,
    IntType.six,
    IntType.seven,
    IntType.eight,
    IntType.nine,
    IntType.zero,
  ];
}


编辑:

感谢 AKS 的回答 解决方法是将Wrap 移动到Scaffold 的正文中

Updated code in DartPad

更新代码:

import 'package:flutter/material.dart';

void main() {
  runApp(MyApp());
}

class MyApp extends StatefulWidget {
  _MyAppState createState() => _MyAppState();
}

class _MyAppState extends State<MyApp> {
  final items = List.generate(400, (index) => '$index');
  final filterOptions = <IntType>[];

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      theme: ThemeData(appBarTheme: AppBarTheme(elevation: 0)),
      home: Scaffold(
        body: buildBody(),
        appBar: AppBar(
          title: Text('Simple filtering'),
        ),
      ),
    );
  }

  Widget buildBody() {
    return Column(
      crossAxisAlignment: CrossAxisAlignment.stretch,
      children: [
        Material(
          elevation: 4,
          child: Container(
            color: Theme.of(context).primaryColor,
            child: Padding(
              padding: const EdgeInsets.all(8.0),
              child: Wrap(
                alignment: WrapAlignment.center,
                spacing: 8,
                children: IntType.values.map((option) {
                  return FilterChip(
                    selectedColor: Colors.white,
                    selected: filterOptions.contains(option),
                    onSelected: (isSelected) {
                      setState(() {
                        if (isSelected) {
                          filterOptions.add(option);
                        } else {
                          filterOptions.remove(option);
                        }
                      });
                    },
                    label: Text(option.name),
                  );
                }).toList(),
              ),
            ),
          ),
        ),
        Expanded(
          child: Scrollbar(
            child: ListView.builder(
              itemCount: items.length,
              itemBuilder: (context, index) {
                final item = items[index];

                if (filterOptions
                    .every((option) => item.contains(option.symbol))) {
                  return ListTile(title: Text(item));
                }

                return Container(height: 0.0001);
              },
            ),
          ),
        ),
      ],
    );
  }
}

class IntType {
  static const IntType one = const IntType._('One', '1');
  static const IntType two = const IntType._('Two', '2');
  static const IntType three = const IntType._('Three', '3');
  static const IntType four = const IntType._('Four', '4');
  static const IntType five = const IntType._('Five', '5');
  static const IntType six = const IntType._('Six', '6');
  static const IntType seven = const IntType._('Seven', '7');
  static const IntType eight = const IntType._('Eight', '8');
  static const IntType nine = const IntType._('Nine', '9');
  static const IntType zero = const IntType._('Zero', '0');

  final String name;
  final String symbol;

  const IntType._(this.name, this.symbol);

  static const values = [
    IntType.one,
    IntType.two,
    IntType.three,
    IntType.four,
    IntType.five,
    IntType.six,
    IntType.seven,
    IntType.eight,
    IntType.nine,
    IntType.zero,
  ];
}


【问题讨论】:

    标签: flutter flutter-appbar


    【解决方案1】:

    不要使用bottomAppbar属性,你应该创建一个Column并添加两个孩子,其中一个用于模拟bottom appBar,另一个用于实际主体并添加@ 987654322@ 小部件在里面,

    这样你可以获得完全相同的小部件结构,而不会妨碍 Appbar 小部件内的文本。

    希望对此解决方案的看法可以帮助您。

    【讨论】:

    • 我想我不明白你的解决方案。如果我需要将 Wrap 添加到正文,为什么我需要 Container?我宁愿需要列。我试图实现这一点,但我无法实现相同的外观和感觉。我不能像以前一样把工作带到相同的海拔高度。但是,要完全删除它需要权衡取舍,但这对我来说不是一个选择。您对此有解决方案吗?
    • 是的,您完全正确,您的代码简直太棒了,我只是想让您感受一下解决方案。您是否还在遇到海拔高度不一致的问题?如果是请上传截图。
    • 现在一切正常。我将高程“移动”到 Wrap,所以看起来 Wrap 实际上是放在 AppBar 底部的。你可以在DartPad自己试一试
    猜你喜欢
    • 1970-01-01
    • 2020-01-02
    • 2018-10-24
    • 1970-01-01
    • 2016-09-24
    • 2019-03-11
    • 2020-05-09
    • 2020-05-16
    • 2018-12-07
    相关资源
    最近更新 更多