强制容器内的小部件将其自身限制为一行

Force widget inside a container to limit itself to one row

我对 Flutter 比较陌生,有一个布局问题,我觉得应该很容易解决。我正在尝试将 MarkdownBody(包含一些 HTML 文本)呈现为 ListTile 的标题。如果标题太长就会溢出。如果我可以使用 Text 小部件而不是 MarkdownBody,那么解决方案将非常简单:使用 maxLines: 1overflow: 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 包装在各种布局小部件中;例如ContainerSizedBoxRowExpanded,但无法解决溢出问题。

我怎样才能做到这一点?

您将不得不修改 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;
  }
}