【问题标题】:Xamarin.Forms UWP - Display HTML in a LabelXamarin.Forms UWP - 在标签中显示 HTML
【发布时间】:2018-04-29 02:48:53
【问题描述】:

在 Xamarin.Forms 中,如何在标签中显示 HTML?换句话说,如果我有new Label { Text = "some text and <b>some bold text</b>" },我希望它显示为“一些文本和一些粗体文本”。

我知道我需要使用自定义渲染器,并且我已经在 iOS 中实现了。我只是不知道如何在 UWP 中实现它。

【问题讨论】:

  • 我有类似的需求,似乎没有任何原生 UWP 控件可以处理它

标签: html xamarin xamarin.forms uwp custom-renderer


【解决方案1】:

根据您的要求,您可以通过自定义LabelRenderer 来实现此功能,在本机项目中您可以将HtmlTextBehavior 设为TextBlock。以下是Behavior处理逻辑。

public class HtmlTextBehavior : Behavior<TextBlock>
{
    private const string ElementA = "A";
    private const string ElementB = "B";
    private const string ElementBr = "BR";
    private const string ElementEm = "EM";
    private const string ElementI = "I";
    private const string ElementP = "P";
    private const string ElementStrong = "STRONG";
    private const string ElementU = "U";
    private const string ElementUl = "UL";
    private const string ElementLi = "LI";
    private const string ElementDiv = "DIV";
    protected override void OnAttached()
    {
        base.OnAttached();

        AssociatedObject.Loaded += OnAssociatedObjectLoaded;
        AssociatedObject.LayoutUpdated += OnAssociatedObjectLayoutUpdated;
    }

    protected override void OnDetaching()
    {
        base.OnDetaching();
        AssociatedObject.Loaded -= OnAssociatedObjectLoaded;
        AssociatedObject.LayoutUpdated -= OnAssociatedObjectLayoutUpdated;
    }

    private void OnAssociatedObjectLayoutUpdated(object sender, object o)
    {
        UpdateText();
    }

    private void OnAssociatedObjectLoaded(object sender, RoutedEventArgs routedEventArgs)
    {
        UpdateText();
        AssociatedObject.Loaded -= OnAssociatedObjectLoaded;
    }

    private void UpdateText()
    {
        if (AssociatedObject == null) return;
        if (string.IsNullOrEmpty(AssociatedObject.Text)) return;

        string text = AssociatedObject.Text;

        // Just incase we are not given text with elements.
        string modifiedText = string.Format("<div>{0}</div>", text);

        // reset the text because we will add to it.
        AssociatedObject.Inlines.Clear();
        try
        {
            var element = XElement.Parse(modifiedText);
            ParseText(element, AssociatedObject.Inlines);
        }
        catch (Exception)
        {
            // if anything goes wrong just show the html
            AssociatedObject.Text = text;
        }
        AssociatedObject.LayoutUpdated -= OnAssociatedObjectLayoutUpdated;
        AssociatedObject.Loaded -= OnAssociatedObjectLoaded;
    }
    private static void ParseText(XElement element, InlineCollection inlines)
    {
        if (element == null) return;

        InlineCollection currentInlines = inlines;
        var elementName = element.Name.ToString().ToUpper();
        switch (elementName)
        {
            case ElementA:
                var link = new Hyperlink();
                var href = element.Attribute("href");
                if (href != null)
                {
                    try
                    {
                        link.NavigateUri = new Uri(href.Value);
                    }
                    catch (System.FormatException) { /* href is not valid */ }
                }
                inlines.Add(link);
                currentInlines = link.Inlines;
                break;
            case ElementB:
            case ElementStrong:
                var bold = new Bold();
                inlines.Add(bold);
                currentInlines = bold.Inlines;
                break;
            case ElementI:
            case ElementEm:
                var italic = new Italic();
                inlines.Add(italic);
                currentInlines = italic.Inlines;
                break;
            case ElementU:
                var underline = new Underline();
                inlines.Add(underline);
                currentInlines = underline.Inlines;
                break;
            case ElementBr:
                inlines.Add(new LineBreak());
                break;
            case ElementP:
                // Add two line breaks, one for the current text and the second for the gap.
                if (AddLineBreakIfNeeded(inlines))
                {
                    inlines.Add(new LineBreak());
                }

                Span paragraphSpan = new Span();
                inlines.Add(paragraphSpan);
                currentInlines = paragraphSpan.Inlines;
                break;
            case ElementLi:
                inlines.Add(new LineBreak());
                inlines.Add(new Run { Text = " • " });
                break;
            case ElementUl:
            case ElementDiv:
                AddLineBreakIfNeeded(inlines);
                Span divSpan = new Span();
                inlines.Add(divSpan);
                currentInlines = divSpan.Inlines;
                break;
        }
        foreach (var node in element.Nodes())
        {
            XText textElement = node as XText;
            if (textElement != null)
            {
                currentInlines.Add(new Run { Text = textElement.Value });
            }
            else
            {
                ParseText(node as XElement, currentInlines);
            }
        }
        // Add newlines for paragraph tags
        if (elementName == "ElementP")
        {
            currentInlines.Add(new LineBreak());
        }
    }
    private static bool AddLineBreakIfNeeded(InlineCollection inlines)
    {
        if (inlines.Count > 0)
        {
            var lastInline = inlines[inlines.Count - 1];
            while ((lastInline is Span))
            {
                var span = (Span)lastInline;
                if (span.Inlines.Count > 0)
                {
                    lastInline = span.Inlines[span.Inlines.Count - 1];
                }
            }
            if (!(lastInline is LineBreak))
            {
                inlines.Add(new LineBreak());
                return true;
            }
        }
        return false;
    }
}

然后您可以将此行为添加到 cusotm 渲染器中的 Native Control

protected override void OnElementChanged(ElementChangedEventArgs<Label> e)
{
    base.OnElementChanged(e);
    HtmlTextBehavior behavior = new HtmlTextBehavior();      
    Interaction.GetBehaviors(Control).Add(behavior);
}

我已上传code sample。请检查。

【讨论】:

    【解决方案2】:

    也许看看这个https://blog.pieeatingninjas.be/2017/11/05/creating-a-hyperlinklabel-in-xamarin-forms/...这可能是一个很好的起点,可以扩展您的需求仍然缺少什么?

    目前只支持超链接,不过标签的处理方式是一样的。

    【讨论】:

    • 这可能行得通——我什至不需要超链接,只需要几个简单的标签来格式化文本,如
    猜你喜欢
    • 2021-11-16
    • 2015-03-03
    • 1970-01-01
    • 2023-01-24
    • 2020-08-27
    • 1970-01-01
    • 1970-01-01
    • 2019-06-11
    • 1970-01-01
    相关资源
    最近更新 更多