【问题标题】:Load markdown text into the Xamarin.Forms Label将 markdown 文本加载到 Xamarin.Forms 标签中
【发布时间】:2018-07-06 07:02:15
【问题描述】:

最近,Xamarin.Forms 标签支持FormattedText。所以我想使用 FormattedText 属性来加载降价文本。例如,

我有以下几种降价文本,

 1. **Hi**, How are you?
 2. Hello **John**, _Good Morning_

我想自动将上面的markdown文本转换为FormattedString以设置为Label.FormattedText。

谁能帮我实现这个目标?

注意:我不想使用第三方 MarkdownView 控件,因为它们是重量级控件,并且在我检查 Xamarin.Forms iOS 时在呈现 UI 时会遇到一些问题。

【问题讨论】:

  • 如果你没有使用3rd-party库,那么自己解析字符串并将其转换为FormattedString的Spans集合
  • @SushiHangover,是的。为此,我只是寻求一些帮助
  • @SushiHangover,实际上,我正在寻找任何已经具备这种解析机制的库,例如 Microsoft.MarkedNet
  • github.com/T-Alex/MarkedNet/tree/master/src/MarkedNet 和 Github 上的许多其他人......
  • 也许这也能让你走上正轨blog.pieeatingninjas.be/2017/11/05/…

标签: xamarin xamarin.forms label markdown formatted-text


【解决方案1】:

最后,我自己写了解析,把markdown文本转换成FormattedString。

public static FormattedString GetFormattedString(this string text, double defaultFontSize)
    {
        var boldFormat = "**";
        var italicFormat = "_";
        var formatString = new FormattedString();
        var temp = text;
        while(!string.IsNullOrWhiteSpace(temp))
        {
            try
            {
                var boldIndex = temp.IndexOf(boldFormat);
                var italicIndex = temp.IndexOf(italicFormat);

                if (italicIndex >= 0 && (italicIndex < boldIndex || boldIndex < 0))
                {
                    if (italicIndex > 0)
                    {
                        var t = temp.Substring(0, italicIndex);
                        formatString.Spans.Add(new Span() { Text = t });
                    }
                    temp = temp.Substring(italicIndex + 1);
                    var next = temp.IndexOf(italicFormat);
                    var t1 = temp.Substring(0, next);
                    formatString.Spans.Add(new Span() { Text = t1, FontAttributes = FontAttributes.Italic, FontSize = defaultFontSize });
                    temp = temp.Substring(next + 1);
                }
                else if (boldIndex >= 0)
                {
                    if (boldIndex > 0)
                    {
                        var t = temp.Substring(0, boldIndex);
                        formatString.Spans.Add(new Span() { Text = t });
                    }
                    temp = temp.Substring(boldIndex + 2);
                    var next = temp.IndexOf(boldFormat);
                    var t1 = temp.Substring(0, next);
                    formatString.Spans.Add(new Span() { Text = t1, FontAttributes = FontAttributes.Bold, FontSize = defaultFontSize });
                    temp = temp.Substring(next + 2);
                }
                else
                {
                    formatString.Spans.Add(new Span() { Text = temp, FontSize = defaultFontSize });
                    break;
                }
            }
            catch (Exception)
            {
                formatString = new FormattedString();
                formatString.Spans.Add(new Span() { Text = text, FontSize = defaultFontSize });
                break;
            }
        }
        return formatString;
    }

注意:目前,我只添加了粗体和斜体格式的代码。需要为所需的降价格式扩展它。

【讨论】:

    【解决方案2】:

    这是一个如何为Microsoft.Toolkit.Parsers 编写自定义渲染器的示例,以便将一些基本的 Markdown 转换为 Xamarin Label FormattedText:

    class LabelMarkdownRenderer : MarkdownRendererBase
    {
        private readonly Stack<MarkdownInlineType> _inlineTypeStack;
    
        private readonly IDictionary<int, Style> _headerStyles;
        private readonly Color _urlLinkColor;
    
        private int _headerLevel;
    
        public LabelMarkdownRenderer(
            MarkdownDocument document,
            Color urlLinkColor,
            IDictionary<int, Style> headerStyles) : base(document)
        {
            _inlineTypeStack = new Stack<MarkdownInlineType>();
            _headerStyles = headerStyles;
            _urlLinkColor = urlLinkColor;
        }
    
        protected override void RenderParagraph(ParagraphBlock element, IRenderContext context)
        {
            if (element.Inlines.Any())
            {
                if (element.Inlines.Any())
                {
                    RenderInlineChildren(element.Inlines, context);
                }
    
                if (context.Parent is FormattedString fs)
                {
                    if (fs.Spans?.Any() ?? false)
                    {
                        fs.Spans.Last().Text += Environment.NewLine;
                    }
                }
            }
        }
    
        protected override void RenderYamlHeader(YamlHeaderBlock element, IRenderContext context)
        {
            //throw new NotImplementedException();
        }
    
        protected override void RenderHeader(HeaderBlock element, IRenderContext context)
        {
            _headerLevel = element.HeaderLevel;
            RenderInlineChildren(element.Inlines, context);
    
            if (context.Parent is FormattedString fs)
            {
                if (fs.Spans?.Any() ?? false)
                {
                    fs.Spans.Last().Text += Environment.NewLine;
                }
    
            }
    
            _headerLevel = 0;
        }
    
        protected override void RenderListElement(ListBlock element, IRenderContext context)
        {
            //throw new NotImplementedException();
        }
    
        protected override void RenderHorizontalRule(IRenderContext context)
        {
            //throw new NotImplementedException();
        }
    
        protected override void RenderQuote(QuoteBlock element, IRenderContext context)
        {
            throw new NotImplementedException();
        }
    
        protected override void RenderCode(CodeBlock element, IRenderContext context)
        {
            //throw new NotImplementedException();
        }
    
        protected override void RenderTable(TableBlock element, IRenderContext context)
        {
            //throw new NotImplementedException();
        }
    
        protected override void RenderEmoji(EmojiInline element, IRenderContext context)
        {
            //throw new NotImplementedException();
        }
    
        protected override void RenderTextRun(TextRunInline element, IRenderContext context)
        {
            if (context.Parent is FormattedString fs)
            {
                var span = new Span
                {
                    Text = element.Text.Replace("\n\r", Environment.NewLine)
                };
    
                if (_headerLevel > 0)
                {
                    span.Style = _headerStyles[_headerLevel];
                }
    
                foreach (var inlineType in _inlineTypeStack)
                {
                    switch (inlineType)
                    {
                        case MarkdownInlineType.Comment:
                        case MarkdownInlineType.TextRun:
                            break;
                        case MarkdownInlineType.Bold:
                            span.FontAttributes += (int)FontAttributes.Bold;
                            break;
                        case MarkdownInlineType.Italic:
                            span.FontAttributes += (int)FontAttributes.Italic;
                            break;
                        case MarkdownInlineType.MarkdownLink:
                            break;
                        case MarkdownInlineType.RawHyperlink:
                            break;
                        case MarkdownInlineType.RawSubreddit:
                            break;
                        case MarkdownInlineType.Strikethrough:
                            span.TextDecorations += (int)TextDecorations.Strikethrough;
                            break;
                        case MarkdownInlineType.Superscript:
                            break;
                        case MarkdownInlineType.Subscript:
                            break;
                        case MarkdownInlineType.Code:
                            break;
                        case MarkdownInlineType.Image:
                            break;
                        case MarkdownInlineType.Emoji:
                            break;
                        case MarkdownInlineType.LinkReference:
                            break;
                        default:
                            throw new ArgumentOutOfRangeException();
                    }
                }
    
                fs.Spans.Add(span);
            }
        }
    
        protected override void RenderBoldRun(BoldTextInline element, IRenderContext context)
        {
            RenderInlineType(element.Inlines, MarkdownInlineType.Bold, context);
        }
    
        protected override void RenderMarkdownLink(MarkdownLinkInline element, IRenderContext context)
        {
            var text = string.Join(string.Empty, element.Inlines);
    
            RenderLink(text, element.Url, context);
        }
    
        protected override void RenderImage(ImageInline element, IRenderContext context)
        {
            //throw new NotImplementedException();
        }
    
        protected override void RenderHyperlink(HyperlinkInline element, IRenderContext context)
        {
            RenderLink(element.Text, element.Url, context);
        }
    
        protected override void RenderItalicRun(ItalicTextInline element, IRenderContext context)
        {
            RenderInlineType(element.Inlines, MarkdownInlineType.Italic, context);
        }
    
        protected override void RenderStrikethroughRun(StrikethroughTextInline element, IRenderContext context)
        {
            //throw new NotImplementedException();
        }
    
        protected override void RenderSuperscriptRun(SuperscriptTextInline element, IRenderContext context)
        {
            //throw new NotImplementedException();
        }
    
        protected override void RenderSubscriptRun(SubscriptTextInline element, IRenderContext context)
        {
            //throw new NotImplementedException();
        }
    
        protected override void RenderCodeRun(CodeInline element, IRenderContext context)
        {
            //throw new NotImplementedException();
        }
    
        private void RenderLink(string text, string url, IRenderContext context)
        {
            if (context.Parent is FormattedString fs)
            {
                var span = new Span
                {
                    Text = text,
                    TextDecorations = TextDecorations.Underline,
                    TextColor = _urlLinkColor
                };
    
                var tap = new TapGestureRecognizer
                {
                    Command = new Command<string>(urlStr => Device.OpenUri(new Uri(urlStr))),
                    CommandParameter = url
                };
    
                span.GestureRecognizers.Add(tap);
    
                fs.Spans.Add(span);
            }
        }
    
        private void RenderInlineType(IList<MarkdownInline> inlines, MarkdownInlineType markdownInlineType, IRenderContext context)
        {
            _inlineTypeStack.Push(markdownInlineType);
            RenderInlineChildren(inlines, context);
            _inlineTypeStack.Pop();
        }
    }
    
    

    有关更多详细信息以及如何将此代码转换为自定义控件扩展 Xamarin Forms 中的标签,请参阅此项目:https://github.com/1iveowl/plugin.label.markdown/blob/master/src/main/Plugin.Label.MarkDown/Renderer/LabelMarkdownRenderer.cs

    【讨论】:

      猜你喜欢
      • 2017-04-13
      • 1970-01-01
      • 2017-12-08
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-11-08
      • 1970-01-01
      相关资源
      最近更新 更多