强制容器内的小部件将其自身限制为一行
Force widget inside a container to limit itself to one row
我对 Flutter 比较陌生,有一个布局问题,我觉得应该很容易解决。我正在尝试将 MarkdownBody
(包含一些 HTML 文本)呈现为 ListTile
的标题。如果标题太长就会溢出。如果我可以使用 Text
小部件而不是 MarkdownBody
,那么解决方案将非常简单:使用 maxLines: 1
和 overflow: TextOverflow.ellipsis
。但是由于标题包含 HTML 我正在使用 MarkdownBody
,所以这就是我创建标题的方式:
return new Container(
height: 25.0,
child: new Row(
crossAxisAlignment: CrossAxisAlignment.start,
mainAxisAlignment: MainAxisAlignment.start,
children: <Widget>[
new Expanded(
child: new MarkdownBody(
data: converted,
styleSheet: MarkdownStyleSheet(
p: textStyle,
strong: TextStyle(fontWeight: FontWeight.bold),
),
),
)
],
),
);
看起来是这样的:
该搜索结果中的每一行都是 ListTile
包裹在 Container
中,其标题和副标题如上所示创建。我想要做的是确保如果文本太长,标题和副标题都被切断。我尝试将 MarkdownBody
包装在各种布局小部件中;例如Container
、SizedBox
、Row
和 Expanded
,但无法解决溢出问题。
我怎样才能做到这一点?
您将不得不修改 markdown 库,特别是 this method:
@override
void visitText(md.Text text) {
if (_blocks.last.tag == null) // Don't allow text directly under the root.
return;
_addParentInlineIfNeeded(_blocks.last.tag);
final TextSpan span = _blocks.last.tag == 'pre'
? delegate.formatText(styleSheet, text.text)
: new TextSpan(
maxLines: 1,
overflow: TextOverflow.ellipsis,
style: _inlines.last.style,
text: text.text,
recognizer: _linkHandlers.isNotEmpty ? _linkHandlers.last : null,
);
_inlines.last.children.add(new RichText(text: span));
}
或者,您可以创建自己的小型 HTML 解析器来组成 TextSpan
(基本上是带格式的文本),然后使用 RichText
小部件呈现它。
理想的解决方案是克隆原始包并在其中添加一个额外的小部件,以便您可以提供 overflow
/maxLines
属性和 interrupt/extend 解析逻辑 overflow
and/or maxLines
设置为限制构建的子项。
假设 markdown 的长度对于你的传入数据来说是最小的,你可以在你自己的项目中扩展 MarkdownWidget
而不是像这样破解它(节省你编写自己的解析器或必须克隆另一个项目):
import 'dart:io';
import 'package:flutter/widgets.dart';
import 'package:flutter_markdown/flutter_markdown.dart';
class SingleLineMarkdownBody extends MarkdownWidget {
final TextOverflow overflow;
final int maxLines;
const SingleLineMarkdownBody(
{Key key,
String data,
MarkdownStyleSheet styleSheet,
SyntaxHighlighter syntaxHighlighter,
MarkdownTapLinkCallback onTapLink,
Directory imageDirectory,
this.overflow,
this.maxLines})
: super(
key: key,
data: data,
styleSheet: styleSheet,
syntaxHighlighter: syntaxHighlighter,
onTapLink: onTapLink,
imageDirectory: imageDirectory,
);
@override
Widget build(BuildContext context, List<Widget> children) {
var richText = _findWidgetOfType<RichText>(children.first);
if (richText != null) {
return RichText(
text: richText.text,
textAlign: richText.textAlign,
textDirection: richText.textDirection,
softWrap: richText.softWrap,
overflow: this.overflow,
textScaleFactor: richText.textScaleFactor,
maxLines: this.maxLines,
locale: richText.locale);
}
return children.first;
}
T _findWidgetOfType<T>(Widget widget) {
if (widget is T) {
return widget as T;
}
if (widget is MultiChildRenderObjectWidget) {
MultiChildRenderObjectWidget multiChild = widget;
for (var child in multiChild.children) {
return _findWidgetOfType<T>(child);
}
} else if (widget is SingleChildRenderObjectWidget) {
SingleChildRenderObjectWidget singleChild = widget;
return _findWidgetOfType<T>(singleChild.child);
}
return null;
}
}
我对 Flutter 比较陌生,有一个布局问题,我觉得应该很容易解决。我正在尝试将 MarkdownBody
(包含一些 HTML 文本)呈现为 ListTile
的标题。如果标题太长就会溢出。如果我可以使用 Text
小部件而不是 MarkdownBody
,那么解决方案将非常简单:使用 maxLines: 1
和 overflow: TextOverflow.ellipsis
。但是由于标题包含 HTML 我正在使用 MarkdownBody
,所以这就是我创建标题的方式:
return new Container(
height: 25.0,
child: new Row(
crossAxisAlignment: CrossAxisAlignment.start,
mainAxisAlignment: MainAxisAlignment.start,
children: <Widget>[
new Expanded(
child: new MarkdownBody(
data: converted,
styleSheet: MarkdownStyleSheet(
p: textStyle,
strong: TextStyle(fontWeight: FontWeight.bold),
),
),
)
],
),
);
看起来是这样的:
该搜索结果中的每一行都是 ListTile
包裹在 Container
中,其标题和副标题如上所示创建。我想要做的是确保如果文本太长,标题和副标题都被切断。我尝试将 MarkdownBody
包装在各种布局小部件中;例如Container
、SizedBox
、Row
和 Expanded
,但无法解决溢出问题。
我怎样才能做到这一点?
您将不得不修改 markdown 库,特别是 this method:
@override
void visitText(md.Text text) {
if (_blocks.last.tag == null) // Don't allow text directly under the root.
return;
_addParentInlineIfNeeded(_blocks.last.tag);
final TextSpan span = _blocks.last.tag == 'pre'
? delegate.formatText(styleSheet, text.text)
: new TextSpan(
maxLines: 1,
overflow: TextOverflow.ellipsis,
style: _inlines.last.style,
text: text.text,
recognizer: _linkHandlers.isNotEmpty ? _linkHandlers.last : null,
);
_inlines.last.children.add(new RichText(text: span));
}
或者,您可以创建自己的小型 HTML 解析器来组成 TextSpan
(基本上是带格式的文本),然后使用 RichText
小部件呈现它。
理想的解决方案是克隆原始包并在其中添加一个额外的小部件,以便您可以提供 overflow
/maxLines
属性和 interrupt/extend 解析逻辑 overflow
and/or maxLines
设置为限制构建的子项。
假设 markdown 的长度对于你的传入数据来说是最小的,你可以在你自己的项目中扩展 MarkdownWidget
而不是像这样破解它(节省你编写自己的解析器或必须克隆另一个项目):
import 'dart:io';
import 'package:flutter/widgets.dart';
import 'package:flutter_markdown/flutter_markdown.dart';
class SingleLineMarkdownBody extends MarkdownWidget {
final TextOverflow overflow;
final int maxLines;
const SingleLineMarkdownBody(
{Key key,
String data,
MarkdownStyleSheet styleSheet,
SyntaxHighlighter syntaxHighlighter,
MarkdownTapLinkCallback onTapLink,
Directory imageDirectory,
this.overflow,
this.maxLines})
: super(
key: key,
data: data,
styleSheet: styleSheet,
syntaxHighlighter: syntaxHighlighter,
onTapLink: onTapLink,
imageDirectory: imageDirectory,
);
@override
Widget build(BuildContext context, List<Widget> children) {
var richText = _findWidgetOfType<RichText>(children.first);
if (richText != null) {
return RichText(
text: richText.text,
textAlign: richText.textAlign,
textDirection: richText.textDirection,
softWrap: richText.softWrap,
overflow: this.overflow,
textScaleFactor: richText.textScaleFactor,
maxLines: this.maxLines,
locale: richText.locale);
}
return children.first;
}
T _findWidgetOfType<T>(Widget widget) {
if (widget is T) {
return widget as T;
}
if (widget is MultiChildRenderObjectWidget) {
MultiChildRenderObjectWidget multiChild = widget;
for (var child in multiChild.children) {
return _findWidgetOfType<T>(child);
}
} else if (widget is SingleChildRenderObjectWidget) {
SingleChildRenderObjectWidget singleChild = widget;
return _findWidgetOfType<T>(singleChild.child);
}
return null;
}
}