使用类似于 textoverflow 的省略号处理行溢出
Handle row overflow using ellipsis similar to textoverflow
我有一行包含多个 children,我想在一行中显示该行的 children。但是,如果没有足够的空间容纳所有 children,我想在行尾显示一个省略号,就像我们有文本的 overflow
和 maxlines
属性一样来处理溢出问题。 row
是否有解决方法?
Row(
children: [
TagItem('Education'),
TagItem('GPA'),
TagItem('Books'),
TagItem('University'),
TagItem('Library'),
],
)
我想要这样的东西:
两种可能的方法:
这是关于 flutter 布局的较难问题之一。有两种方法,一种有点难,另一种更难。如果需要,我可以提供一些示例代码,但我会先在这里描述方法,看看你是否可以自己做。
使用CustomMultiChildLayout
。在这个小部件中,您可以(几乎)完全控制 flutter 布局管道,您可以测量总可用大小,更重要的是,您可以测量每个 children 的大小,然后确定要做什么使成为。此解决方案的缺点是,您无法根据 children 的大小设置 parent (CustomMultiChildLayout
) 的大小。在您的情况下,这意味着您无法动态决定小部件的高度。如果使用 SizedBox
(例如 height: 120
或其他)设置固定高度听起来合理,您应该采用这种方法。
写你自己的RenderBox
。在你的情况下,你应该考虑扩展 MultiChildRenderObjectWidget
。基本上,您每天使用的所有这些方便的小部件,如 Row
或 Column
,都是 RenderBox
的幕后黑手(那些从事 Flutter 工作的人已经为您实现了)。因此,如果这些不足以满足您的需求,您可以随时创造更多!
使用方法 #1 的概念证明:
采用固定高度的自定义 RowWithOverflow
小部件、溢出小部件和所有 children。
用法示例:
RowWithOverflow(
height: 100,
overflow: Chip(label: Text('...')),
children: [
Chip(label: Text('Item 1')),
Chip(label: Text('Item 2')),
Chip(label: Text('Item 3')),
],
)
演示应用程序:
演示应用的源代码:
import 'package:flutter/material.dart';
void main() {
runApp(const MyApp());
}
class MyApp extends StatefulWidget {
const MyApp({Key? key}) : super(key: key);
@override
State<MyApp> createState() => _MyAppState();
}
class _MyAppState extends State<MyApp> {
int _count = 3;
@override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
appBar: AppBar(),
body: Column(
children: [
Text('CustomMultiChildLayout demo:'),
RowWithOverflow(
height: 50,
overflow: Chip(label: Text('...')),
children: [
for (int i = 0; i < _count; i++)
Padding(
padding: const EdgeInsets.symmetric(horizontal: 1.0),
child: Chip(label: Text('Item $i')),
),
],
),
ElevatedButton(
onPressed: () => setState(() => _count += 1),
child: Text('Add item'),
),
],
),
),
);
}
}
class RowWithOverflow extends StatelessWidget {
final double height;
final List<Widget> children;
final Widget overflow;
const RowWithOverflow({
Key? key,
required this.height,
required this.children,
required this.overflow,
}) : super(key: key);
@override
Widget build(BuildContext context) {
return SizedBox(
height: height,
child: ClipRect(
child: CustomMultiChildLayout(
delegate: MyDelegate(children.length),
children: [
for (int i = 0; i < children.length; i++)
LayoutId(
id: i,
child: children[i],
),
LayoutId(
id: 'overflow',
child: overflow,
),
],
),
),
);
}
}
class MyDelegate extends MultiChildLayoutDelegate {
final int _childrenCount;
MyDelegate(this._childrenCount);
@override
void performLayout(Size size) {
// Get the size of the overflow item.
final Size overflowSize = layoutChild(
'overflow',
BoxConstraints.loose(size),
);
// Get sizes of all children.
final List<Size> childrenSizes = [
for (int i = 0; i < _childrenCount; i++)
layoutChild(i, BoxConstraints.loose(size)),
];
// Hide everything for now.
positionChild('overflow', Offset(0, -2000));
for (int i = 0; i < _childrenCount; i++) {
positionChild(i, Offset(0, -2000));
}
// Carefully position each child until we run out of space.
Offset offset = Offset.zero;
for (int i = 0; i < _childrenCount; i++) {
if (offset.dx + childrenSizes[i].width < size.width) {
positionChild(i, offset);
offset += Offset(childrenSizes[i].width, 0);
} else {
positionChild('overflow', offset);
offset = Offset(0, 200);
break;
}
}
}
@override
bool shouldRelayout(oldDelegate) => false;
}
我有一行包含多个 children,我想在一行中显示该行的 children。但是,如果没有足够的空间容纳所有 children,我想在行尾显示一个省略号,就像我们有文本的 overflow
和 maxlines
属性一样来处理溢出问题。 row
是否有解决方法?
Row(
children: [
TagItem('Education'),
TagItem('GPA'),
TagItem('Books'),
TagItem('University'),
TagItem('Library'),
],
)
我想要这样的东西:
两种可能的方法:
这是关于 flutter 布局的较难问题之一。有两种方法,一种有点难,另一种更难。如果需要,我可以提供一些示例代码,但我会先在这里描述方法,看看你是否可以自己做。
使用
CustomMultiChildLayout
。在这个小部件中,您可以(几乎)完全控制 flutter 布局管道,您可以测量总可用大小,更重要的是,您可以测量每个 children 的大小,然后确定要做什么使成为。此解决方案的缺点是,您无法根据 children 的大小设置 parent (CustomMultiChildLayout
) 的大小。在您的情况下,这意味着您无法动态决定小部件的高度。如果使用SizedBox
(例如height: 120
或其他)设置固定高度听起来合理,您应该采用这种方法。写你自己的
RenderBox
。在你的情况下,你应该考虑扩展MultiChildRenderObjectWidget
。基本上,您每天使用的所有这些方便的小部件,如Row
或Column
,都是RenderBox
的幕后黑手(那些从事 Flutter 工作的人已经为您实现了)。因此,如果这些不足以满足您的需求,您可以随时创造更多!
使用方法 #1 的概念证明:
采用固定高度的自定义 RowWithOverflow
小部件、溢出小部件和所有 children。
用法示例:
RowWithOverflow(
height: 100,
overflow: Chip(label: Text('...')),
children: [
Chip(label: Text('Item 1')),
Chip(label: Text('Item 2')),
Chip(label: Text('Item 3')),
],
)
演示应用程序:
演示应用的源代码:
import 'package:flutter/material.dart';
void main() {
runApp(const MyApp());
}
class MyApp extends StatefulWidget {
const MyApp({Key? key}) : super(key: key);
@override
State<MyApp> createState() => _MyAppState();
}
class _MyAppState extends State<MyApp> {
int _count = 3;
@override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
appBar: AppBar(),
body: Column(
children: [
Text('CustomMultiChildLayout demo:'),
RowWithOverflow(
height: 50,
overflow: Chip(label: Text('...')),
children: [
for (int i = 0; i < _count; i++)
Padding(
padding: const EdgeInsets.symmetric(horizontal: 1.0),
child: Chip(label: Text('Item $i')),
),
],
),
ElevatedButton(
onPressed: () => setState(() => _count += 1),
child: Text('Add item'),
),
],
),
),
);
}
}
class RowWithOverflow extends StatelessWidget {
final double height;
final List<Widget> children;
final Widget overflow;
const RowWithOverflow({
Key? key,
required this.height,
required this.children,
required this.overflow,
}) : super(key: key);
@override
Widget build(BuildContext context) {
return SizedBox(
height: height,
child: ClipRect(
child: CustomMultiChildLayout(
delegate: MyDelegate(children.length),
children: [
for (int i = 0; i < children.length; i++)
LayoutId(
id: i,
child: children[i],
),
LayoutId(
id: 'overflow',
child: overflow,
),
],
),
),
);
}
}
class MyDelegate extends MultiChildLayoutDelegate {
final int _childrenCount;
MyDelegate(this._childrenCount);
@override
void performLayout(Size size) {
// Get the size of the overflow item.
final Size overflowSize = layoutChild(
'overflow',
BoxConstraints.loose(size),
);
// Get sizes of all children.
final List<Size> childrenSizes = [
for (int i = 0; i < _childrenCount; i++)
layoutChild(i, BoxConstraints.loose(size)),
];
// Hide everything for now.
positionChild('overflow', Offset(0, -2000));
for (int i = 0; i < _childrenCount; i++) {
positionChild(i, Offset(0, -2000));
}
// Carefully position each child until we run out of space.
Offset offset = Offset.zero;
for (int i = 0; i < _childrenCount; i++) {
if (offset.dx + childrenSizes[i].width < size.width) {
positionChild(i, offset);
offset += Offset(childrenSizes[i].width, 0);
} else {
positionChild('overflow', offset);
offset = Offset(0, 200);
break;
}
}
}
@override
bool shouldRelayout(oldDelegate) => false;
}