Reputation: 2548
I am relatively new to Flutter and having a layout problem that I feel should be easy to do. I am trying to render a MarkdownBody
(that contains some HTML text) as the title of a ListTile
. If the title is too long it overflows. If I could use a Text
widget instead of a MarkdownBody
then the solution would be very easy: use maxLines: 1
and overflow: TextOverflow.ellipsis
. But since the title contains HTML I am using MarkdownBody
, so that's how I am creating the title:
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),
),
),
)
],
),
);
That's how it looks like:
Each row in that search result is a ListTile
wrapped inside a Container
, where its title and subtitle are created as shown above. What I am trying to do is to make sure that both title and subtitle are cut off if the text is too long. I tried wrapping the MarkdownBody
inside various layout widgets; e.g. Container
, SizedBox
, Row
with Expanded
, but couldn't fix the overflow problem.
How can I achieve this?
Upvotes: 0
Views: 1636
Reputation: 16319
The ideal solution would be to clone the original package and add an extra widget in there so that you can provide overflow
/maxLines
properties and interrupt/extend the parsing logic when overflow
and/or maxLines
is set to limit the children that get built.
Working on the assumption that the length of the markdown is minimal for your incoming data, you could just extend MarkdownWidget
in your own project instead and hack it in like this (saves you writing your own parser or having to clone another project):
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;
}
}
Upvotes: 4
Reputation: 30103
You will have to modify the markdown library, in particular 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));
}
Alternatively, you could create your own small HTML parser that composes a TextSpan
(basically text with format), then render it using a RichText
widget.
Upvotes: 1