asjqkkkk / markdown_widget

📖Rendering markdown by flutter!Welcome for pr and issue.
MIT License
321 stars 93 forks source link

请教一下作者,如何能够实现输出行数的限制? #124

Closed deng-cc closed 1 year ago

deng-cc commented 1 year ago

我在试着开发一款卡片笔记向的app,想要实现卡片内容"展开/收起"的功能,因为需要渲染markdown所以无法使用Text组件(maxLines),MarkdownWidget我看了里面是ListView,我考虑是否能从外部设置 itemCount,但很可惜无法。

我也尝试了通过比如SIzedBox来设定height实现,但是效果不太好,行数限制也不准确。

所以请教一下是否有什么方式可以实现这个需求,或者是否可以加上诸如 maxItemCount 属性供使用?

谢谢 :D

hoangduchuu commented 1 year ago

@deng-cc

我在试着开发一款卡片笔记向的app,想要实现卡片内容"展开/收起"的功能,因为需要渲染markdown所以无法使用Text组件(maxLines),MarkdownWidget我看了里面是ListView,我考虑是否能从外部设置 itemCount,但很可惜无法。

我也尝试了通过比如SIzedBox来设定height实现,但是效果不太好,行数限制也不准确。

所以请教一下是否有什么方式可以实现这个需求,或者是否可以加上诸如 maxItemCount 属性供使用?

谢谢 :D

@deng-cc How about this feature?

deng-cc commented 1 year ago

@deng-cc

我在试着开发一款卡片笔记向的app,想要实现卡片内容"展开/收起"的功能,因为需要渲染markdown所以无法使用Text组件(maxLines),MarkdownWidget我看了里面是ListView,我考虑是否能从外部设置 itemCount,但很可惜无法。 我也尝试了通过比如SIzedBox来设定height实现,但是效果不太好,行数限制也不准确。 所以请教一下是否有什么方式可以实现这个需求,或者是否可以加上诸如 maxItemCount 属性供使用? 谢谢 :D

@deng-cc How about this feature?

I tried modifying the "itemCount: _widgets.length" in the markdown_widget to a specific number for testing, but I found that it didn't have the effect I expected. So I temporarily closed the issue and decided to try more again to see if there are other possibilities.

hoangduchuu commented 1 year ago

@deng-cc

我在试着开发一款卡片笔记向的app,想要实现卡片内容"展开/收起"的功能,因为需要渲染markdown所以无法使用Text组件(maxLines),MarkdownWidget我看了里面是ListView,我考虑是否能从外部设置 itemCount,但很可惜无法。 我也尝试了通过比如SIzedBox来设定height实现,但是效果不太好,行数限制也不准确。 所以请教一下是否有什么方式可以实现这个需求,或者是否可以加上诸如 maxItemCount 属性供使用? 谢谢 :D

@deng-cc How about this feature?

I tried modifying the "itemCount: _widgets.length" in the markdown_widget to a specific number for testing, but I found that it didn't have the effect I expected. So I temporarily closed the issue and decided to try more again to see if there are other possibilities.

@deng-cc means you can't limit the maxLines by set itemCount: 2, right?

deng-cc commented 1 year ago

I tried modifying the "itemCount: _widgets.length" in the markdown_widget to a specific number for testing, but I found that it didn't have the effect I expected. So I temporarily closed the issue and decided to try more again to see if there are other possibilities.

@deng-cc means you can't limit the maxLines by set itemCount: 2, right?

@hoangduchuu actually you can limit the parsed-block but not line, I'll give you some examples:

when you change the itemCount to 1 and your markdown content is below:

hello
world

you will got still all lines larger than 1

hello
world

because they became one parsed-block which means they are 1 itemCount

if the markdown content like this below ( I added a blank line )

hello

world

you will got

hello

because they became two parsed-block, and the 'hello' is the first one, so only show that one.

you can see details in the markdown_generator.dart line40:

final List<m.Node> nodes = document.parseLines(lines);

deng-cc commented 1 year ago

I reopen this issue and asking for more help.

asjqkkkk commented 1 year ago

@deng-cc 你好,因为Text的内容都是文本,所以可以计算出高度然后实现展开/收起的功能

但是markdown中都是富文本,并且可能出现类似图片这样无法提前确定高度的组件,同时可能还存在许多自定义的组件也是无法提前确认高度的,所以目前看来它并不适合去对输出行数作为限制条件,因为每一行的表现并不是一样的

推荐换一种方式去实现这个功能,就是将行数限制改为高度限制,卡片的展开方式可以从之前的文本末端出现展开按钮,变更为卡片底部悬浮的展开按钮

deng-cc commented 1 year ago

@asjqkkkk 确实我没有考虑到图片这种渲染的情况,感谢作者的解释和启发 😘

目前我用了一种不太完美的方式,通过单纯计算渲染前的文本进行截断以后,再来进行渲染,问题在于有些markdown语法因为截断会丢失导致渲染失败,后期我会试下作者的思路,再次感谢。

我的代码也贴一下,如果有其他网友需要的话可以参考:

class TextUtils {
  /// 返回限制后的文本
  static LimitTextResult limitText({
    required String text,
    required TextStyle style,
    required double maxWidth,
    required int maxLines,
    bool? showEllipsis = true,
  }) {
    final tp = TextPainter(
      text: TextSpan(text: text, style: style),
      maxLines: maxLines,
      textDirection: TextDirection.ltr,
    );
    tp.layout(maxWidth: maxWidth);
    LimitTextResult result = LimitTextResult(text: text, isLimit: false);
    if (tp.didExceedMaxLines) {
      final lastLine = text.substring(0, tp.getPositionForOffset(Offset(tp.width, tp.height)).offset);
      String str = lastLine.trim();
      result.text = showEllipsis! ? '$str\n...' : str;
      result.isLimit = true;
    }
    return result;
  }
}

class LimitTextResult {
  String text;
  bool isLimit;

  LimitTextResult({
    required this.text,
    required this.isLimit,
  });

  LimitTextResult.init()
      : text = '',
        isLimit = false;
}
...
child: LayoutBuilder(
    builder: (context, constraints) {
      LimitTextResult limit = TextUtils.limitText(
        text: widget.content,
        style: contentStyle,
        maxWidth: constraints.maxWidth,
        maxLines: maxLines,
      );
      return Column(
        crossAxisAlignment: CrossAxisAlignment.end,
        children: [
          NoteMarkdownWidget(
            context: context,
            selectable: false,
            data: isExpanded ? widget.content : limit.text,
            shrinkWrap: true,
            physics: const NeverScrollableScrollPhysics(),
          ),
          limit.isLimit
              ? GestureDetector(
                  child: Text(isExpanded ? '收起' : '展开', style: layoutStyle),
                  onTap: () {
                    setState(() => isExpanded = !isExpanded);
                  },
                )
              : const Text('')
        ],
      );
    },
  ),
...

那么这个问题我就先关闭了~