当前位置: 首页 > 知识库问答 >
问题:

flutter - Flutter 状态栏与 FloatingActionButton 的布局问题?

王佐
2024-04-28

flutter 状态栏问题
当我设置0的时候 floatingActionButton 显示正常
image.png
当我设置一点高度为什么会这样?
image.png

这是什么原因导致的?

希望知道原因 我想 floatingActionButton 可以在Appbar下边

共有1个答案

糜宜民
2024-04-28
建议:
  • 不推荐下面的写法,因为AppBar已经实现了PreferredSizeWidget(Widgets like AppBar implement a PreferredSizeWidget, so that this PreferredSize widget is not necessary for them)

    PreferredSize(      preferredSize: const Size.fromHeight(1),      child:  AppBar(          centerTitle: true,          title: const Text('状态栏与FloatingActionButton 的布局问题?'),          backgroundColor: Colors.yellow,        ),    ),
  • 可以像下面这样自定义的AppBar,参考这个例子

    PreferredSize(      preferredSize: const Size.fromHeight(1),      child:  YourCustomWigde(         child: child,        ),    ),
  • 如果非要要preferredSize的child是一个AppBar可以像下面这样,也可以把ConstrainedBox 换成SizedBox(height:0);其实就是 Size.fromHeight(0)的效果,把0换成其他的数字也是可以的

     PreferredSize(      preferredSize: const Size.fromHeight(1),      child: ConstrainedBox(        constraints: const  BoxConstraints(maxHeight: 0),        child: AppBar(          centerTitle: true,          title: const Text('状态栏与FloatingActionButton 的布局问题?'),          backgroundColor: Colors.yellow,        ),      ),    ),
为什么要添加ConstrainedBox、SizedBox :

下面是我的Build方法实现,和你上面的不太一样;如果把ConstrainedBox去掉就会出现类似你那种的情况

 Widget build(BuildContext context) {    return Scaffold(      appBar: PreferredSize(        preferredSize: const Size.fromHeight(1),        child: ConstrainedBox(          constraints: const BoxConstraints(maxHeight: 0),          child: AppBar(            centerTitle: true,            title: const Text('状态栏与FloatingActionButton 的布局问题?'),            backgroundColor: Colors.yellow,          ),        ),      ),      body: const Center(        child: Text('This is Content'),      ),      floatingActionButtonLocation: FloatingActionButtonLocation.centerTop,      floatingActionButton: const ColoredBox(        color: Colors.red,        child: Column(          children: [            Text('A'),            Text('B'),            Text('C'),            Text('DDDDDDDDDDDDDDDDD'),            Text('E'),            Text(              'F',              style: TextStyle(color: Colors.yellow),            ),          ],        ),      ),    );  }
  1. 现在的出现的问题是FloatingActionButton位置不对,内容被部分遮挡了,第一想到就是添加SafeArea避免被遮挡,但是没有效果;(我猜想Scaffold类似一个Stack组件而FloatingActionButton是一个Position组件)
  2. 打开Android Studio的Flutter Inspector查看FloatingActionButton布局后的数据也就是查看top,bottom,width,height;但没有找到top,bootom的数据,只有ColoredBox的Size(width,height)(如果你知道的话请告知��)
  3. 接下来打断点,跟着代码运行一下看看FloatingActionButton布局时的top数据;
    下面是scaffold.dart文件中 performLayout方法部分实现,我的flutter版本:3.19.5

    if (hasChild(_ScaffoldSlot.floatingActionButton)) {   final Size fabSize = layoutChild(_ScaffoldSlot.floatingActionButton, looseConstraints);   // To account for the FAB position being changed, we'll animate between   // the old and new positions.   final ScaffoldPrelayoutGeometry currentGeometry = ScaffoldPrelayoutGeometry(     bottomSheetSize: bottomSheetSize,     contentBottom: contentBottom,     /// [appBarHeight] should be used instead of [contentTop] because     /// ScaffoldPrelayoutGeometry.contentTop must not be affected by [extendBodyBehindAppBar].     contentTop: appBarHeight,     floatingActionButtonSize: fabSize,     minInsets: minInsets,     scaffoldSize: size,     snackBarSize: snackBarSize,     materialBannerSize: materialBannerSize,     textDirection: textDirection,     minViewPadding: minViewPadding,   );   final Offset currentFabOffset = currentFloatingActionButtonLocation.getOffset(currentGeometry);   final Offset previousFabOffset = previousFloatingActionButtonLocation.getOffset(currentGeometry);   final Offset fabOffset = floatingActionButtonMotionAnimator.getOffset(     begin: previousFabOffset,     end: currentFabOffset,     progress: floatingActionButtonMoveAnimationProgress,   );   positionChild(_ScaffoldSlot.floatingActionButton, fabOffset);   floatingActionButtonRect = fabOffset & fabSize; }

其中floatingActionButton的位置由fabOffset和fabSize决定;而fabSize只有宽度和高度; 我门还需要fabOffset才能确定floatingActionButton的位置;previousFloatingActionButtonLocation、currentFloatingActionButtonLocation是为了计算之前和现在位置的差值进行动画用的;例子中的floatingActionButton的位置是固定的;所以currentFloatingActionButtonLocation 数值等于previousFloatingActionButtonLocation 并且等于 fabOffset(根据显示的数据能判断是相等的,内部实现代码省略); 所以获取currentFloatingActionButtonLocation就可以获取floatingActionButton的top值; 下面代码是getOffset的实现;位于floting_action_button_location.dart 文件中

Offset getOffset(ScaffoldPrelayoutGeometry scaffoldGeometry) {    final double adjustment = isMini() ? kMiniButtonOffsetAdjustment : 0.0;    return Offset(      getOffsetX(scaffoldGeometry, adjustment),      getOffsetY(scaffoldGeometry, adjustment),    );  }

因为例子中floatingActionButton的X轴方向布局是没有问题的,所以下面代码中只关心 getOffsetY(scaffoldGeometry, adjustment)的实现,此时 scaffoldGeometry.contentTop = 25,scaffoldGeometry.minViewPadding.top = 24;scaffoldGeometry.floatingActionButtonSize.height = 737.45454545;所以 scaffoldGeometry.contentTop - fabHalfHeight = -343.7 所以 currentFloatingActionButtonLocation 这个偏移量top值就是-343.7;也就是floatingActionButton的top值等于 -343.7, 这就造成了floatingActionButton显示不完全

mixin FabTopOffsetY on StandardFabLocation {  /// Calculates y-offset for [FloatingActionButtonLocation]s floating over  /// the transition between the [Scaffold.appBar] and the [Scaffold.body].  @override  double getOffsetY(ScaffoldPrelayoutGeometry scaffoldGeometry, double adjustment) {    if (scaffoldGeometry.contentTop > scaffoldGeometry.minViewPadding.top) {      final double fabHalfHeight = scaffoldGeometry.floatingActionButtonSize.height / 2.0;      return scaffoldGeometry.contentTop - fabHalfHeight;    }    // Otherwise, ensure we are placed within the bounds of a safe area.    return scaffoldGeometry.minViewPadding.top;  }}

看一下上面scaffold.dart文件中 performLayout方法部分实现中scaffoldGeometry.contentTop的值等于appBarHeight;appBarHeight的定义如下:

 double appBarHeight = 0.0;    if (hasChild(_ScaffoldSlot.appBar)) {      appBarHeight = layoutChild(_ScaffoldSlot.appBar, fullWidthConstraints).height;      contentTop = extendBodyBehindAppBar ? 0.0 : appBarHeight;      positionChild(_ScaffoldSlot.appBar, Offset.zero);    }

上面layoutChild这个方法会布局appBar,appBar会循环布局里面的子组件,然后返回最后的高度和宽度;这里的appBarHeight等于appBar布局后的高度,这里是25;而不是1;所以才想到添加ConstrainedBox或者SizedBox 强制约束来强制设置AppBar高度;

AppBar布局后高度为什么是25尼? ����
上面最最最有价值的地方是解决问题的思路,一定要慢慢培养
 类似资料:
  • 页面布局代码如下,第一次打开页面Column里三个组件是紧挨着的,零点几秒后才MainAxisAlignment.spaceBetween分开,时间虽然不是很久但是肉眼还是可见的有点延迟,请问是因为什么原因?

  • 我有一个带有。我们的客户要求我们根据从中选择的项目,动态更改此活动的操作栏颜色和相应的状态栏颜色。这很容易做到。然而,我的问题是,当我动态更改状态栏颜色时,我无法保持状态栏透明。当我打开抽屉时,彩色状态栏会覆盖抽屉布局的顶部,如下所示: 但是,我希望我的看起来像这样: 这我可以用下面的行做: 然而,我的问题不是我不能设置状态栏的透明度。我的问题是,状态栏和操作栏颜色的动态更改不适用于。我的状态栏颜

  • 我知道有成千上万个这样的问题,但是我尝试了所有的方法,但是我不能想出一个解决方案。基本上,我使用的是NoActionBar风格的活动。 风格。xml: v21/风格。xml: 家庭活动正常,抽屉将在透明状态栏下正常打开: 问题是使用以下布局的另一个活动: 基本上,状态栏是透明的,所以我看不到它,因为我的colorPrimary是白色的。奇怪的是,如果我折叠工具栏(因此只有选项卡可见),状态栏将正确

  • 我注意到当打开我的应用程序时,有两个屏幕可以到达我的第一个颤动屏幕 1-1屏幕有灰色或(50%透明)状态和导航栏黑色和浅色图标。2-2屏幕有100%透明的状态和导航栏和白色图标。 我怎么能让所有的屏幕像第一次颤动屏幕100透明状态和导航栏与黑色图标(亮度暗)。 第一屏 第二屏 第一个颤振筛 风格xml 主要活动。kt 编辑 现在我已经改变了我的代码,第一个屏幕是正确的,但第二个屏幕仍然图标是白色的

  • 本文向大家介绍Flutter 透明状态栏及字体颜色的设置方法,包括了Flutter 透明状态栏及字体颜色的设置方法的使用技巧和注意事项,需要的朋友参考一下 注:底色透明是否生效与android版本有关,版本过低设置无效 1.在main.dart内设置 2.单页面设置 注:设置AppBar之后,单独在build内设置这行代码会失效 SystemChrome.setSystemUIOverlaySty

  • 本文向大家介绍Flutter自动换行和两列布局,包括了Flutter自动换行和两列布局的使用技巧和注意事项,需要的朋友参考一下 Row 和 Column 是 Flex 组件,是无法滚动的,如果没有足够的空间,flutter就提示溢出错误。 这种情况下,Expanded 或 Flexible 组件可用作长文本的自动换行。 在 Flutter文档中 虽然没有明确说明,但是在主轴上如有内容超出空间, E