如何检测小部件中的溢出

Tab*_*aba 5 flutter flutter-layout flutter-widget

我想知道是否有办法检测小部件中发生的溢出并返回一个布尔值以根据trueorfalse值进行一些更改。

例如,我有一个里面有文字的容器。我想检测文本何时溢出容器,之后我将在某些条件下使容器变大。我知道有一些方法,auto_size_text但这里的重点是检测溢出

Spa*_*atz 6

使用TextPainter我们可以测量文本的宽度,使用LayoutBuilder我们可以确定边界框:

import 'package:flutter/material.dart';

class Demo extends StatefulWidget {
  @override
  _DemoState createState() => _DemoState();
}

class _DemoState extends State<Demo> {
  String text = "text";

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(),
      floatingActionButton: FloatingActionButton(
        child: Icon(Icons.add),
        onPressed: () {
          setState(() {
            text += " text";
          });
        },
      ),
      body: Padding(
        padding: const EdgeInsets.all(32.0),
        child: LayoutBuilder(
          builder: (ctx, constraints) {
            final style = Theme.of(context).textTheme.headline1;
            final span = TextSpan(
              text: text,
              style: style,
            );
            final painter = TextPainter(
              text: span,
              maxLines: 1,
              textScaleFactor: MediaQuery.of(context).textScaleFactor,
              textDirection: TextDirection.ltr,
            );
            painter.layout();
            final overflow = painter.size.width > constraints.maxWidth;
            return Container(
              color: overflow ? Colors.red : Colors.green,
              child: Text.rich(span, style: style),
            );
          },
        ),
      ),
    );
  }
}
Run Code Online (Sandbox Code Playgroud)

CodePen 上的演示


use*_*613 5

试图检测何时发生溢出,对我来说看起来像是XY 问题

在 Flutter 中,子小部件的大小受其父小部件的限制,很少有可能发生溢出的情况。例如,考虑下面的代码:

Container(
  height: 100,
  width: 100,
  color: Colors.red,
  child: Container(
    width: 200,
    height: 800,
    color: Colors.green,
  ),
)
Run Code Online (Sandbox Code Playgroud)

对于没有经验的 Flutter 开发人员来说,内部 Container (200x800) 看起来可能会溢出其父级 (100x100),但实际上,内部 Container 的大小会自动调整以匹配其父级,因此您不会看到黑色/黄色溢出条纹,您只会在屏幕上看到一个 100x100 的绿色容器。

那么,我们什么时候可以期待孩子们在 Flutter 中溢出呢?通常有 4 种情况会导致溢出:

  1. 软硬度:很常用的ColumnRow小部件是由继承Flex部件,您也可以直接使用。在这些小部件中,当执行布局时,它们将在其主轴上传递一个“无界”约束。例如,在 a 的情况下Column,它的主轴是垂直轴,所以它允许它的子节点有他们想要的任何高度(但不是多宽)。如果其子项的组合高度超过其Column自身的布局约束(由 Column 的父项向下传递),它将溢出。基本上,如果将 Column 放入 100x100 Container 中,则 Column 的高度不能超过 100,如果它的子项超过,它就会溢出。

对于这些情况,检测是可行的,但通常是不必要的。例如,要检测,您可以首先使用LayoutBuilder获取Column自身的父母约束,这样您就知道您可能拥有的最大尺寸是多少(比如 100x100,因为 Column 被放置在这样的 Container 中),然后您需要获取每个孩子的大小,这对于 Column 来说不太容易,因为在布局过程完成之前你不会知道他们的大小。(如果您必须在布局完成之前知道它们的大小,您可以考虑查看CustomMultiChildLayout或编写自定义RenderBox)。您也许可以使用GlobalKey来获取任何小部件的大小,但是一旦第一次布置子项,就必须在下一帧中完成。

也许在这里问一个更好的问题是:你为什么想知道它是否会溢出?如果它溢出,你能做什么?如果可以为 Column 分配更多空间,那为什么不首先这样做呢?您可以设置MainAxisSize.minColumn 以告诉它缩小,除非确实需要,否则不要浪费所有这些额外空间。或者,也许您想允许滚​​动?如果是这样,只需Column用一个SingleChildScrollView小部件将整个包装起来,它就会在 Column 长得太高时自动开始滚动。(顺便说一句,这与 using 不同ListViewListView如果您有很多项目要滚动,则应该使用。)

  1. 堆栈:堆栈中的小部件,尤其是那些小部件,Positioned如果您故意这样做,可能会溢出堆栈。例如,通过设置,left: -10, top: -20您有意在边界之外渲染一个小部件(左上角一点点)。但是堆栈会自动为您剪辑,因此您甚至看不到那些溢出的内容。要查看它们,您实际上需要手动更改clipBehavior堆栈的 。如果您正在做所有这些工作,我认为“检测算法”并不是完全必要的。

  2. 文本:文本很棘手,取决于字体大小(甚至可能由用户在系统级别修改)、字体粗细、字体系列和许多其他因素,很难计算一个段落将占用多少空间。这是TextPainter可以用来帮助您进行所有计算的地方,layout首先是文本,然后您可以读取其宽度和高度。

  3. 溢出框:Flutter 中其他可能溢出的方法是有意使用诸如OverflowBoxSizedOverflowBox等之类的小部件。这些小部件故意打破父约束,但如果您正在使用这些,我相信您知道自己在做什么。根据用例,您可以考虑使用CustomMultiChildLayout获取每个孩子的大小,然后再决定放置它们的位置。

最后评论:因为您可能想要一个“通用解决方案”,所以这里是:在 Flutter 中,大多数事情都不能溢出。如果需要,LayoutBuilder小部件可用于确定小部件的当前布局约束,因此您知道父母希望您成为的最大和最小尺寸。要获得子小部件的大小,最好的方法是在布局过程中使用CustomSingleChildLayoutCustomMultiChildLayout在布局过程中使用。要获取屏幕上已有的任何小部件的大小和位置,您可以使用GlobalKey. 然而,通常更重要的是考虑为什么要知道这些尺寸,而不是如何获得它们。