我想知道是否有办法检测部件中发生的溢出并返回一个布尔值,以便根据true
或false
值进行一些更改。
例如,我有一个包含文本的Container。我想要检测当文本溢出容器时,我将使用一些条件使容器变大。我知道有一些方法,如auto_size_text
,但重点在于检测溢出。
我想知道是否有办法检测部件中发生的溢出并返回一个布尔值,以便根据true
或false
值进行一些更改。
例如,我有一个包含文本的Container。我想要检测当文本溢出容器时,我将使用一些条件使容器变大。我知道有一些方法,如auto_size_text
,但重点在于检测溢出。
试图检测溢出发生的时候,对我来说看起来像是一个XY问题。让我们停下来思考一下:为什么我们想要检测溢出?当它溢出时我们能做些什么呢?
在Flutter中,子小部件的大小受其父级限制,很少出现溢出的情况。例如,考虑下面的代码:
Container(
height: 100,
width: 100,
color: Colors.red,
child: Container(
width: 200,
height: 800,
color: Colors.green,
),
)
Stack:堆栈中的小部件,特别是那些定位小部件,如果您故意这样做,可以溢出堆栈。例如,通过设置 left: -10, top: -20
,您知ingly地呈现小部件在边界之外(略微超过左上角)。但是堆栈会自动为您剪辑它,所以您甚至看不到那些溢出的内容。要查看它们,实际上需要手动更改堆栈的 clipBehavior
。如果您正在进行所有这些工作,我认为“检测算法”并不是必需的。
Text:文本很棘手,具体取决于字体大小(甚至可能被用户在系统级别修改),字重,字体系列和许多其他因素,很难计算出一个段落将占用多少空间。这就是 TextPainter
可以用来帮助您进行所有计算的地方,layout
首先对文本进行布局,然后您可以读取其宽度和高度。
OverflowBox:Flutter 中其他可能的溢出方式是有意使用诸如 OverflowBox
或 SizedOverflowBox
等小部件。这些小部件有意打破了父约束,但是如果您使用这些小部件,我相信您知道自己在做什么。根据用例,您可以考虑使用 CustomMultiChildLayout
在决定放置它们之前获取每个子级的大小。
最后的备注:由于您可能想要一个“通用解决方案”,因此这里是:在 Flutter 中,大多数事情都不能溢出。如果需要,可以使用 LayoutBuilder
小部件来确定小部件的当前布局约束,以便您知道父项希望您的最大和最小大小。要获取子小部件的大小,最好的方法是在布局过程中使用 CustomSingleChildLayout
或 CustomMultiChildLayout
。要获取屏幕上已经存在的任何小部件的大小和位置,可以使用 GlobalKey
。但是,更重要的是考虑为什么要知道这些大小,而不是如何获得它们。
Image
的fit
属性)已经发生了,对吗?此外,由于您将容器设置为200x200,而不是检测图像是否会溢出,那么识别图像的分辨率、宽高比等是否更容易呢?换句话说,如果您让它正确地fit
,即使是一个巨大的2000x2000图像也不会在50x50的容器中溢出。 - WSBTCustomMultiChildLayout
等类似方法,您可以在决定如何定位它们之前访问每个子项的大小。如果您编写自己的渲染对象,则还可以访问黄色条纹。该条纹通常是通过DebugOverflowIndicatorMixin
完成的,您可以阅读相关文档,或者如果您提出一个新问题(并将链接发送给我),我可以回答并提供一些代码示例。 - WSBT使用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),
);
},
),
),
);
}
}
代码笔上的演示
import 'package:flutter/material.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
visualDensity: VisualDensity.adaptivePlatformDensity,
),
home: MyHomePage(title: 'Flutter Demo Home Page'),
);
}
}
class MyHomePage extends StatefulWidget {
MyHomePage({Key key, this.title}) : super(key: key);
final String title;
@override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
var dimension = 40.0;
increaseWidgetSize() {
setState(() {
dimension += 20;
});
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(widget.title),
),
body: Center(
child: Column(children: <Widget>[
Text('Dimension: $dimension'),
Container(
color: Colors.teal,
alignment: Alignment.center,
height: dimension,
width: dimension,
// LayoutBuilder inherits its parent widget's dimension. In this case, the Container in teal
child: LayoutBuilder(builder: (context, constraints) {
debugPrint('Max height: ${constraints.maxHeight}, max width: ${constraints.maxWidth}');
return Container(); // create function here to adapt to the parent widget's constraints
}),
),
]),
),
floatingActionButton: FloatingActionButton(
onPressed: increaseWidgetSize,
tooltip: 'Increment',
child: Icon(Icons.add),
),
);
}
}
height = MediaQuery.of(context).size.height;
weight = MediaQuery.of(context).size.width;
我认为改变容器的大小不是一个好主意,如果容器再次溢出其父级怎么办?正确的方法是使用auto_size_text来调整容器内部的文本大小:
AutoSizeText(
'The text to display',
style: TextStyle(fontSize: 20),
maxLines: 2,
)