Make Label display HTML from a string (#4527)
* Use UpdateText * Added missing helper method and UI test * Added missing helper for UWP * Added csproj entry for helper * Resolved rebase conflicts * Update LabelRenderer.cs * Update LabelRenderer.cs * Update LabelRenderer.cs * iOS Merge error fix * Feedback * - uwp fixes * - android fix empty text * - ios fix null and setting text when texttype starts as html * - set _perfectSizeValid = false; after changed AttributedText Setting the AttributedText causes GetDesiredSize to get called which sets _perfectSizeValid to true but at this point this frame still hasn't adjusted to any size change from *LayoutSubViews*. This resets _perfectSizeValid so after the AttributedText set the desiredsize can get pulled again * Renamed PlainText to Text * Fixed initial no HTML styling
This commit is contained in:
Родитель
c0a681e852
Коммит
938a840e68
|
@ -0,0 +1,88 @@
|
||||||
|
using System;
|
||||||
|
using Xamarin.Forms.CustomAttributes;
|
||||||
|
using Xamarin.Forms.Internals;
|
||||||
|
|
||||||
|
#if UITEST
|
||||||
|
using Xamarin.Forms.Core.UITests;
|
||||||
|
using Xamarin.UITest;
|
||||||
|
using NUnit.Framework;
|
||||||
|
using System.Linq;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
namespace Xamarin.Forms.Controls.Issues
|
||||||
|
{
|
||||||
|
#if UITEST
|
||||||
|
[Category(UITestCategories.Label)]
|
||||||
|
#endif
|
||||||
|
[Preserve(AllMembers = true)]
|
||||||
|
[Issue(IssueTracker.None, 0, "Implementation of Label TextType", PlatformAffected.All)]
|
||||||
|
public class LabelTextType : TestContentPage
|
||||||
|
{
|
||||||
|
protected override void Init()
|
||||||
|
{
|
||||||
|
var label = new Label
|
||||||
|
{
|
||||||
|
AutomationId = "TextTypeLabel",
|
||||||
|
Text = "<h1>Hello World!</h1>"
|
||||||
|
};
|
||||||
|
|
||||||
|
var button = new Button
|
||||||
|
{
|
||||||
|
AutomationId = "ToggleTextTypeButton",
|
||||||
|
Text = "Toggle HTML/Plain"
|
||||||
|
};
|
||||||
|
|
||||||
|
button.Clicked += (s, a) =>
|
||||||
|
{
|
||||||
|
label.TextType = label.TextType == TextType.Html ? TextType.Text : TextType.Html;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
Label htmlLabel = new Label() { TextType = TextType.Html };
|
||||||
|
Label normalLabel = new Label();
|
||||||
|
Label nullLabel = new Label() { TextType = TextType.Html };
|
||||||
|
|
||||||
|
Button toggle = new Button()
|
||||||
|
{
|
||||||
|
Text = "Toggle some more things",
|
||||||
|
Command = new Command(() =>
|
||||||
|
{
|
||||||
|
htmlLabel.Text = $"<b>{DateTime.UtcNow}</b>";
|
||||||
|
normalLabel.Text = $"<b>{DateTime.UtcNow}</b>";
|
||||||
|
|
||||||
|
if (String.IsNullOrWhiteSpace(nullLabel.Text))
|
||||||
|
nullLabel.Text = "hi there";
|
||||||
|
else
|
||||||
|
nullLabel.Text = null;
|
||||||
|
})
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
var stacklayout = new StackLayout();
|
||||||
|
stacklayout.Children.Add(label);
|
||||||
|
stacklayout.Children.Add(button);
|
||||||
|
stacklayout.Children.Add(htmlLabel);
|
||||||
|
stacklayout.Children.Add(normalLabel);
|
||||||
|
stacklayout.Children.Add(nullLabel);
|
||||||
|
stacklayout.Children.Add(toggle);
|
||||||
|
|
||||||
|
Content = stacklayout;
|
||||||
|
}
|
||||||
|
|
||||||
|
#if UITEST
|
||||||
|
[Test]
|
||||||
|
public void LabelToggleHtmlAndPlainTextTest()
|
||||||
|
{
|
||||||
|
RunningApp.WaitForElement ("TextTypeLabel");
|
||||||
|
RunningApp.Screenshot ("I see plain text");
|
||||||
|
|
||||||
|
Assert.IsTrue(RunningApp.Query("TextTypeLabel").FirstOrDefault()?.Text == "<h1>Hello World!</h1>");
|
||||||
|
|
||||||
|
RunningApp.Tap("ToggleTextTypeButton");
|
||||||
|
RunningApp.Screenshot ("I see HTML text");
|
||||||
|
|
||||||
|
Assert.IsFalse(RunningApp.Query("TextTypeLabel").FirstOrDefault()?.Text.Contains("<h1>") ?? true);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
}
|
|
@ -1029,6 +1029,7 @@
|
||||||
<Compile Include="$(MSBuildThisFileDirectory)Issue6738.cs" />
|
<Compile Include="$(MSBuildThisFileDirectory)Issue6738.cs" />
|
||||||
<Compile Include="$(MSBuildThisFileDirectory)GitHub6926.cs" />
|
<Compile Include="$(MSBuildThisFileDirectory)GitHub6926.cs" />
|
||||||
<Compile Include="$(MSBuildThisFileDirectory)Issue5503.cs" />
|
<Compile Include="$(MSBuildThisFileDirectory)Issue5503.cs" />
|
||||||
|
<Compile Include="$(MSBuildThisFileDirectory)LabelTextType.cs" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<EmbeddedResource Include="$(MSBuildThisFileDirectory)Bugzilla22229.xaml">
|
<EmbeddedResource Include="$(MSBuildThisFileDirectory)Bugzilla22229.xaml">
|
||||||
|
|
|
@ -237,6 +237,40 @@ namespace Xamarin.Forms.Controls
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
|
var htmlLabelContainer = new ViewContainer<Label>(Test.Label.TextType,
|
||||||
|
new Label
|
||||||
|
{
|
||||||
|
Text = "<h1>Hello world!</h1>",
|
||||||
|
TextType = TextType.Html
|
||||||
|
});
|
||||||
|
|
||||||
|
var htmlLabelMultipleLinesContainer = new ViewContainer<Label>(Test.Label.TextType,
|
||||||
|
new Label
|
||||||
|
{
|
||||||
|
Text = "<h1>Hello world!</h1><p>Lorem <strong>ipsum</strong> bla di bla <i>blabla</i> blablabl ablabla & blablablablabl ablabl ablablabl ablablabla blablablablablablab lablablabla blablab lablablabla blablabl ablablablab lablabla blab lablablabla blablab lablabla blablablablab lablabla blablab lablablabl ablablabla blablablablablabla blablabla</p>",
|
||||||
|
TextType = TextType.Html,
|
||||||
|
MaxLines = 3
|
||||||
|
});
|
||||||
|
|
||||||
|
var toggleLabel = new Label
|
||||||
|
{
|
||||||
|
TextType = TextType.Html,
|
||||||
|
Text = "<h1 style=\"color: red;\">Hello world!</h1><p>Lorem <strong>ipsum</strong></p>"
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
var gestureRecognizer = new TapGestureRecognizer();
|
||||||
|
|
||||||
|
gestureRecognizer.Tapped += (s, a) =>
|
||||||
|
{
|
||||||
|
toggleLabel.TextType = toggleLabel.TextType == TextType.Html ? TextType.Text : TextType.Html;
|
||||||
|
};
|
||||||
|
|
||||||
|
toggleLabel.GestureRecognizers.Add(gestureRecognizer);
|
||||||
|
|
||||||
|
var toggleHtmlPlainTextLabelContainer = new ViewContainer<Label>(Test.Label.TextType,
|
||||||
|
toggleLabel);
|
||||||
|
|
||||||
Add (namedSizeMediumBoldContainer);
|
Add (namedSizeMediumBoldContainer);
|
||||||
Add (namedSizeMediumItalicContainer);
|
Add (namedSizeMediumItalicContainer);
|
||||||
Add (namedSizeMediumUnderlineContainer);
|
Add (namedSizeMediumUnderlineContainer);
|
||||||
|
@ -272,6 +306,9 @@ namespace Xamarin.Forms.Controls
|
||||||
Add (maxlinesTailTruncContainer);
|
Add (maxlinesTailTruncContainer);
|
||||||
Add (maxlinesWordWrapContainer);
|
Add (maxlinesWordWrapContainer);
|
||||||
Add(paddingContainer);
|
Add(paddingContainer);
|
||||||
|
Add (htmlLabelContainer);
|
||||||
|
Add (htmlLabelMultipleLinesContainer);
|
||||||
|
Add (toggleHtmlPlainTextLabelContainer);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -90,6 +90,9 @@ namespace Xamarin.Forms
|
||||||
|
|
||||||
public static readonly BindableProperty PaddingProperty = PaddingElement.PaddingProperty;
|
public static readonly BindableProperty PaddingProperty = PaddingElement.PaddingProperty;
|
||||||
|
|
||||||
|
public static readonly BindableProperty TextTypeProperty = BindableProperty.Create(nameof(TextType), typeof(TextType), typeof(Label), TextType.Text,
|
||||||
|
propertyChanged: (bindable, oldvalue, newvalue) => ((Label)bindable).InvalidateMeasureInternal(InvalidationTrigger.MeasureChanged));
|
||||||
|
|
||||||
readonly Lazy<PlatformConfigurationRegistry<Label>> _platformConfigurationRegistry;
|
readonly Lazy<PlatformConfigurationRegistry<Label>> _platformConfigurationRegistry;
|
||||||
|
|
||||||
public Label()
|
public Label()
|
||||||
|
@ -213,6 +216,12 @@ namespace Xamarin.Forms
|
||||||
set { SetValue(PaddingProperty, value); }
|
set { SetValue(PaddingProperty, value); }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public TextType TextType
|
||||||
|
{
|
||||||
|
get => (TextType)GetValue(TextTypeProperty);
|
||||||
|
set => SetValue(TextTypeProperty, value);
|
||||||
|
}
|
||||||
|
|
||||||
double IFontElement.FontSizeDefaultValueCreator() =>
|
double IFontElement.FontSizeDefaultValueCreator() =>
|
||||||
Device.GetNamedSize(NamedSize.Default, (Label)this);
|
Device.GetNamedSize(NamedSize.Default, (Label)this);
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,8 @@
|
||||||
|
namespace Xamarin.Forms
|
||||||
|
{
|
||||||
|
public enum TextType
|
||||||
|
{
|
||||||
|
Text,
|
||||||
|
Html
|
||||||
|
}
|
||||||
|
}
|
|
@ -635,7 +635,8 @@ namespace Xamarin.Forms.CustomAttributes
|
||||||
VerticalTextAlignmentStart,
|
VerticalTextAlignmentStart,
|
||||||
VerticalTextAlignmentCenter,
|
VerticalTextAlignmentCenter,
|
||||||
VerticalTextAlignmentEnd,
|
VerticalTextAlignmentEnd,
|
||||||
MaxLines
|
MaxLines,
|
||||||
|
TextType
|
||||||
}
|
}
|
||||||
|
|
||||||
public enum MasterDetailPage
|
public enum MasterDetailPage
|
||||||
|
|
|
@ -251,6 +251,7 @@ namespace Xamarin.Forms.Platform.Android.FastRenderers
|
||||||
UpdateGravity();
|
UpdateGravity();
|
||||||
if (e.OldElement?.MaxLines != e.NewElement.MaxLines)
|
if (e.OldElement?.MaxLines != e.NewElement.MaxLines)
|
||||||
UpdateMaxLines();
|
UpdateMaxLines();
|
||||||
|
|
||||||
UpdatePadding();
|
UpdatePadding();
|
||||||
|
|
||||||
ElevationHelper.SetElevation(this, e.NewElement);
|
ElevationHelper.SetElevation(this, e.NewElement);
|
||||||
|
@ -263,7 +264,8 @@ namespace Xamarin.Forms.Platform.Android.FastRenderers
|
||||||
|
|
||||||
if (e.PropertyName == Label.HorizontalTextAlignmentProperty.PropertyName || e.PropertyName == Label.VerticalTextAlignmentProperty.PropertyName)
|
if (e.PropertyName == Label.HorizontalTextAlignmentProperty.PropertyName || e.PropertyName == Label.VerticalTextAlignmentProperty.PropertyName)
|
||||||
UpdateGravity();
|
UpdateGravity();
|
||||||
else if (e.PropertyName == Label.TextColorProperty.PropertyName)
|
else if (e.PropertyName == Label.TextColorProperty.PropertyName ||
|
||||||
|
e.PropertyName == Label.TextTypeProperty.PropertyName)
|
||||||
UpdateText();
|
UpdateText();
|
||||||
else if (e.PropertyName == Label.FontProperty.PropertyName)
|
else if (e.PropertyName == Label.FontProperty.PropertyName)
|
||||||
UpdateText();
|
UpdateText();
|
||||||
|
@ -380,7 +382,23 @@ namespace Xamarin.Forms.Platform.Android.FastRenderers
|
||||||
SetTextColor(_labelTextColorDefault);
|
SetTextColor(_labelTextColorDefault);
|
||||||
_lastUpdateColor = Color.Default;
|
_lastUpdateColor = Color.Default;
|
||||||
}
|
}
|
||||||
Text = Element.Text;
|
|
||||||
|
switch (Element.TextType)
|
||||||
|
{
|
||||||
|
case TextType.Html:
|
||||||
|
if (Forms.IsNougatOrNewer)
|
||||||
|
Control.SetText(Html.FromHtml(Element.Text ?? string.Empty, FromHtmlOptions.ModeCompact), BufferType.Spannable);
|
||||||
|
else
|
||||||
|
#pragma warning disable CS0618 // Type or member is obsolete
|
||||||
|
Control.SetText(Html.FromHtml(Element.Text ?? string.Empty), BufferType.Spannable);
|
||||||
|
#pragma warning restore CS0618 // Type or member is obsolete
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
Text = Element.Text;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
UpdateColor();
|
UpdateColor();
|
||||||
UpdateFont();
|
UpdateFont();
|
||||||
|
|
||||||
|
|
|
@ -56,6 +56,7 @@ namespace Xamarin.Forms
|
||||||
static BuildVersionCodes? s_sdkInt;
|
static BuildVersionCodes? s_sdkInt;
|
||||||
static bool? s_isLollipopOrNewer;
|
static bool? s_isLollipopOrNewer;
|
||||||
static bool? s_isMarshmallowOrNewer;
|
static bool? s_isMarshmallowOrNewer;
|
||||||
|
static bool? s_isNougatOrNewer;
|
||||||
|
|
||||||
[Obsolete("Context is obsolete as of version 2.5. Please use a local context instead.")]
|
[Obsolete("Context is obsolete as of version 2.5. Please use a local context instead.")]
|
||||||
[EditorBrowsable(EditorBrowsableState.Never)]
|
[EditorBrowsable(EditorBrowsableState.Never)]
|
||||||
|
@ -98,6 +99,16 @@ namespace Xamarin.Forms
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
internal static bool IsNougatOrNewer
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
if (!s_isNougatOrNewer.HasValue)
|
||||||
|
s_isNougatOrNewer = (int)Build.VERSION.SdkInt >= 24;
|
||||||
|
return s_isNougatOrNewer.Value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public static float GetFontSizeNormal(Context context)
|
public static float GetFontSizeNormal(Context context)
|
||||||
{
|
{
|
||||||
float size = 50;
|
float size = 50;
|
||||||
|
|
|
@ -135,7 +135,6 @@ namespace Xamarin.Forms.Platform.Android
|
||||||
UpdateMaxLines();
|
UpdateMaxLines();
|
||||||
if (e.OldElement.CharacterSpacing != e.NewElement.CharacterSpacing)
|
if (e.OldElement.CharacterSpacing != e.NewElement.CharacterSpacing)
|
||||||
UpdateCharacterSpacing();
|
UpdateCharacterSpacing();
|
||||||
|
|
||||||
}
|
}
|
||||||
UpdateTextDecorations();
|
UpdateTextDecorations();
|
||||||
UpdatePadding();
|
UpdatePadding();
|
||||||
|
@ -158,13 +157,13 @@ namespace Xamarin.Forms.Platform.Android
|
||||||
UpdateLineBreakMode();
|
UpdateLineBreakMode();
|
||||||
else if (e.PropertyName == Label.TextDecorationsProperty.PropertyName)
|
else if (e.PropertyName == Label.TextDecorationsProperty.PropertyName)
|
||||||
UpdateTextDecorations();
|
UpdateTextDecorations();
|
||||||
else if (e.PropertyName == Label.TextProperty.PropertyName || e.PropertyName == Label.FormattedTextProperty.PropertyName)
|
else if (e.IsOneOf(Label.TextProperty, Label.FormattedTextProperty, Label.TextTypeProperty))
|
||||||
UpdateText();
|
UpdateText();
|
||||||
else if (e.PropertyName == Label.LineHeightProperty.PropertyName)
|
else if (e.PropertyName == Label.LineHeightProperty.PropertyName)
|
||||||
UpdateLineHeight();
|
UpdateLineHeight();
|
||||||
else if (e.PropertyName == Label.MaxLinesProperty.PropertyName)
|
else if (e.PropertyName == Label.MaxLinesProperty.PropertyName)
|
||||||
UpdateMaxLines();
|
UpdateMaxLines();
|
||||||
else if (e.PropertyName == ImageButton.PaddingProperty.PropertyName)
|
else if (e.PropertyName == Label.PaddingProperty.PropertyName)
|
||||||
UpdatePadding();
|
UpdatePadding();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -242,7 +241,6 @@ namespace Xamarin.Forms.Platform.Android
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void UpdateLineHeight()
|
void UpdateLineHeight()
|
||||||
{
|
{
|
||||||
_lastSizeRequest = null;
|
_lastSizeRequest = null;
|
||||||
|
@ -274,7 +272,25 @@ namespace Xamarin.Forms.Platform.Android
|
||||||
_view.SetTextColor(_labelTextColorDefault);
|
_view.SetTextColor(_labelTextColorDefault);
|
||||||
_lastUpdateColor = Color.Default;
|
_lastUpdateColor = Color.Default;
|
||||||
}
|
}
|
||||||
_view.Text = Element.Text;
|
|
||||||
|
switch (Element.TextType)
|
||||||
|
{
|
||||||
|
|
||||||
|
case TextType.Html:
|
||||||
|
if (Forms.IsNougatOrNewer)
|
||||||
|
Control.SetText(Html.FromHtml(Element.Text ?? string.Empty, FromHtmlOptions.ModeCompact), TextView.BufferType.Spannable);
|
||||||
|
else
|
||||||
|
#pragma warning disable CS0618 // Type or member is obsolete
|
||||||
|
Control.SetText(Html.FromHtml(Element.Text ?? string.Empty), TextView.BufferType.Spannable);
|
||||||
|
#pragma warning restore CS0618 // Type or member is obsolete
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
_view.Text = Element.Text;
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
UpdateColor();
|
UpdateColor();
|
||||||
UpdateFont();
|
UpdateFont();
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,112 @@
|
||||||
|
using System.Xml.Linq;
|
||||||
|
using Windows.UI.Xaml.Documents;
|
||||||
|
|
||||||
|
namespace Xamarin.Forms.Platform.UAP
|
||||||
|
{
|
||||||
|
internal static class LabelHtmlHelper
|
||||||
|
{
|
||||||
|
// All the supported HTML tags
|
||||||
|
internal const string ElementB = "B";
|
||||||
|
internal const string ElementBr = "BR";
|
||||||
|
internal const string ElementEm = "EM";
|
||||||
|
internal const string ElementI = "I";
|
||||||
|
internal const string ElementP = "P";
|
||||||
|
internal const string ElementStrong = "STRONG";
|
||||||
|
internal const string ElementU = "U";
|
||||||
|
internal const string ElementUl = "UL";
|
||||||
|
internal const string ElementLi = "LI";
|
||||||
|
internal const string ElementDiv = "DIV";
|
||||||
|
|
||||||
|
public static void ParseText(XElement element, InlineCollection inlines, Label label)
|
||||||
|
{
|
||||||
|
if (element == null)
|
||||||
|
return;
|
||||||
|
|
||||||
|
var currentInlines = inlines;
|
||||||
|
var elementName = element.Name.ToString().ToUpper();
|
||||||
|
switch (elementName)
|
||||||
|
{
|
||||||
|
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());
|
||||||
|
}
|
||||||
|
|
||||||
|
var paragraphSpan = new Windows.UI.Xaml.Documents.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);
|
||||||
|
var divSpan = new Windows.UI.Xaml.Documents.Span();
|
||||||
|
inlines.Add(divSpan);
|
||||||
|
currentInlines = divSpan.Inlines;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
foreach (var node in element.Nodes())
|
||||||
|
{
|
||||||
|
if (node is XText textElement)
|
||||||
|
{
|
||||||
|
currentInlines.Add(new Run { Text = textElement.Value });
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
ParseText(node as XElement, currentInlines, label);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Add newlines for paragraph tags
|
||||||
|
if (elementName == "ElementP")
|
||||||
|
{
|
||||||
|
currentInlines.Add(new LineBreak());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool AddLineBreakIfNeeded(InlineCollection inlines)
|
||||||
|
{
|
||||||
|
if (inlines.Count <= 0)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
var lastInline = inlines[inlines.Count - 1];
|
||||||
|
while ((lastInline is Windows.UI.Xaml.Documents.Span))
|
||||||
|
{
|
||||||
|
var span = (Windows.UI.Xaml.Documents.Span)lastInline;
|
||||||
|
if (span.Inlines.Count > 0)
|
||||||
|
{
|
||||||
|
lastInline = span.Inlines[span.Inlines.Count - 1];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (lastInline is LineBreak)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
inlines.Add(new LineBreak());
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,12 +1,15 @@
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.ComponentModel;
|
using System.ComponentModel;
|
||||||
|
using System.Text.RegularExpressions;
|
||||||
|
using System.Xml.Linq;
|
||||||
using Windows.Foundation;
|
using Windows.Foundation;
|
||||||
using Windows.UI.Text;
|
using Windows.UI.Text;
|
||||||
using Windows.UI.Xaml;
|
using Windows.UI.Xaml;
|
||||||
using Windows.UI.Xaml.Automation.Peers;
|
using Windows.UI.Xaml.Automation.Peers;
|
||||||
using Windows.UI.Xaml.Controls;
|
using Windows.UI.Xaml.Controls;
|
||||||
using Windows.UI.Xaml.Documents;
|
using Windows.UI.Xaml.Documents;
|
||||||
|
using Xamarin.Forms.Platform.UAP;
|
||||||
using Xamarin.Forms.PlatformConfiguration.WindowsSpecific;
|
using Xamarin.Forms.PlatformConfiguration.WindowsSpecific;
|
||||||
using Specifics = Xamarin.Forms.PlatformConfiguration.WindowsSpecific.Label;
|
using Specifics = Xamarin.Forms.PlatformConfiguration.WindowsSpecific.Label;
|
||||||
using WThickness = Windows.UI.Xaml.Thickness;
|
using WThickness = Windows.UI.Xaml.Thickness;
|
||||||
|
@ -155,11 +158,8 @@ namespace Xamarin.Forms.Platform.UWP
|
||||||
|
|
||||||
protected override void OnElementPropertyChanged(object sender, PropertyChangedEventArgs e)
|
protected override void OnElementPropertyChanged(object sender, PropertyChangedEventArgs e)
|
||||||
{
|
{
|
||||||
if (e.PropertyName == Label.TextProperty.PropertyName ||
|
if (e.IsOneOf(Label.TextProperty, Label.FormattedTextProperty, Label.TextTypeProperty))
|
||||||
e.PropertyName == Label.FormattedTextProperty.PropertyName)
|
|
||||||
{
|
|
||||||
UpdateText(Control);
|
UpdateText(Control);
|
||||||
}
|
|
||||||
else if (e.PropertyName == Label.TextColorProperty.PropertyName)
|
else if (e.PropertyName == Label.TextColorProperty.PropertyName)
|
||||||
UpdateColor(Control);
|
UpdateColor(Control);
|
||||||
else if (e.PropertyName == Label.HorizontalTextAlignmentProperty.PropertyName || e.PropertyName == Label.VerticalTextAlignmentProperty.PropertyName)
|
else if (e.PropertyName == Label.HorizontalTextAlignmentProperty.PropertyName || e.PropertyName == Label.VerticalTextAlignmentProperty.PropertyName)
|
||||||
|
@ -182,6 +182,7 @@ namespace Xamarin.Forms.Platform.UWP
|
||||||
UpdateMaxLines(Control);
|
UpdateMaxLines(Control);
|
||||||
else if (e.PropertyName == Label.PaddingProperty.PropertyName)
|
else if (e.PropertyName == Label.PaddingProperty.PropertyName)
|
||||||
UpdatePadding(Control);
|
UpdatePadding(Control);
|
||||||
|
|
||||||
base.OnElementPropertyChanged(sender, e);
|
base.OnElementPropertyChanged(sender, e);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -327,10 +328,22 @@ namespace Xamarin.Forms.Platform.UWP
|
||||||
_perfectSizeValid = false;
|
_perfectSizeValid = false;
|
||||||
|
|
||||||
if (textBlock == null)
|
if (textBlock == null)
|
||||||
{
|
|
||||||
return;
|
return;
|
||||||
}
|
|
||||||
|
|
||||||
|
switch (Element.TextType)
|
||||||
|
{
|
||||||
|
case TextType.Html:
|
||||||
|
UpdateTextHtml(textBlock);
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
UpdateTextPlainText(textBlock);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void UpdateTextPlainText(TextBlock textBlock)
|
||||||
|
{
|
||||||
Label label = Element;
|
Label label = Element;
|
||||||
if (label != null)
|
if (label != null)
|
||||||
{
|
{
|
||||||
|
@ -360,6 +373,27 @@ namespace Xamarin.Forms.Platform.UWP
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void UpdateTextHtml(TextBlock textBlock)
|
||||||
|
{
|
||||||
|
var text = Element.Text ?? String.Empty;
|
||||||
|
|
||||||
|
// Just in case we are not given text with elements.
|
||||||
|
var modifiedText = string.Format("<div>{0}</div>", text);
|
||||||
|
modifiedText = Regex.Replace(modifiedText, "<br>", "<br></br>", RegexOptions.IgnoreCase);
|
||||||
|
// reset the text because we will add to it.
|
||||||
|
Control.Inlines.Clear();
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var element = XElement.Parse(modifiedText);
|
||||||
|
LabelHtmlHelper.ParseText(element, Control.Inlines, Element);
|
||||||
|
}
|
||||||
|
catch (Exception)
|
||||||
|
{
|
||||||
|
// if anything goes wrong just show the html
|
||||||
|
textBlock.Text = Windows.Data.Html.HtmlUtilities.ConvertToText(Element.Text);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void UpdateDetectReadingOrderFromContent(TextBlock textBlock)
|
void UpdateDetectReadingOrderFromContent(TextBlock textBlock)
|
||||||
{
|
{
|
||||||
if (Element.IsSet(Specifics.DetectReadingOrderFromContentProperty))
|
if (Element.IsSet(Specifics.DetectReadingOrderFromContentProperty))
|
||||||
|
|
|
@ -78,6 +78,7 @@
|
||||||
<Compile Include="ITitleViewRendererController.cs" />
|
<Compile Include="ITitleViewRendererController.cs" />
|
||||||
<Compile Include="IToolbarProvider.cs" />
|
<Compile Include="IToolbarProvider.cs" />
|
||||||
<Compile Include="IVisualNativeElementRenderer.cs" />
|
<Compile Include="IVisualNativeElementRenderer.cs" />
|
||||||
|
<Compile Include="LabelHtmlHelper.cs" />
|
||||||
<Compile Include="NativeBindingExtensions.cs" />
|
<Compile Include="NativeBindingExtensions.cs" />
|
||||||
<Compile Include="NativeEventWrapper.cs" />
|
<Compile Include="NativeEventWrapper.cs" />
|
||||||
<Compile Include="NativePropertyListener.cs" />
|
<Compile Include="NativePropertyListener.cs" />
|
||||||
|
|
|
@ -39,7 +39,8 @@ namespace Xamarin.Forms.Platform.MacOS
|
||||||
Label.FormattedTextProperty.PropertyName,
|
Label.FormattedTextProperty.PropertyName,
|
||||||
Label.LineBreakModeProperty.PropertyName,
|
Label.LineBreakModeProperty.PropertyName,
|
||||||
Label.LineHeightProperty.PropertyName,
|
Label.LineHeightProperty.PropertyName,
|
||||||
Label.PaddingProperty.PropertyName
|
Label.PaddingProperty.PropertyName,
|
||||||
|
Label.TextTypeProperty.PropertyName
|
||||||
};
|
};
|
||||||
|
|
||||||
public override SizeRequest GetDesiredSize(double widthConstraint, double heightConstraint)
|
public override SizeRequest GetDesiredSize(double widthConstraint, double heightConstraint)
|
||||||
|
@ -216,9 +217,10 @@ namespace Xamarin.Forms.Platform.MacOS
|
||||||
UpdateMaxLines();
|
UpdateMaxLines();
|
||||||
else if (e.PropertyName == Label.PaddingProperty.PropertyName)
|
else if (e.PropertyName == Label.PaddingProperty.PropertyName)
|
||||||
UpdatePadding();
|
UpdatePadding();
|
||||||
|
else if (e.PropertyName == Label.TextTypeProperty.PropertyName)
|
||||||
|
UpdateText();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
protected override NativeLabel CreateNativeControl()
|
protected override NativeLabel CreateNativeControl()
|
||||||
{
|
{
|
||||||
#if __MOBILE__
|
#if __MOBILE__
|
||||||
|
@ -236,6 +238,9 @@ namespace Xamarin.Forms.Platform.MacOS
|
||||||
|
|
||||||
void UpdateTextDecorations()
|
void UpdateTextDecorations()
|
||||||
{
|
{
|
||||||
|
if (Element?.TextType != TextType.Text)
|
||||||
|
return;
|
||||||
|
|
||||||
if (!Element.IsSet(Label.TextDecorationsProperty))
|
if (!Element.IsSet(Label.TextDecorationsProperty))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
@ -275,6 +280,7 @@ namespace Xamarin.Forms.Platform.MacOS
|
||||||
#else
|
#else
|
||||||
Control.AttributedStringValue = newAttributedText;
|
Control.AttributedStringValue = newAttributedText;
|
||||||
#endif
|
#endif
|
||||||
|
_perfectSizeValid = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
#if __MOBILE__
|
#if __MOBILE__
|
||||||
|
@ -372,14 +378,33 @@ namespace Xamarin.Forms.Platform.MacOS
|
||||||
{
|
{
|
||||||
#if __MOBILE__
|
#if __MOBILE__
|
||||||
|
|
||||||
|
if (Element?.TextType != TextType.Text)
|
||||||
|
return;
|
||||||
|
|
||||||
var textAttr = Control.AttributedText.AddCharacterSpacing(Element.Text, Element.CharacterSpacing);
|
var textAttr = Control.AttributedText.AddCharacterSpacing(Element.Text, Element.CharacterSpacing);
|
||||||
|
|
||||||
if (textAttr != null)
|
if (textAttr != null)
|
||||||
Control.AttributedText = textAttr;
|
Control.AttributedText = textAttr;
|
||||||
|
|
||||||
|
_perfectSizeValid = false;
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
void UpdateText()
|
void UpdateText()
|
||||||
|
{
|
||||||
|
switch (Element.TextType)
|
||||||
|
{
|
||||||
|
case TextType.Html:
|
||||||
|
UpdateTextHtml();
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
UpdateTextPlainText();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void UpdateTextPlainText()
|
||||||
{
|
{
|
||||||
_formatted = Element.FormattedText;
|
_formatted = Element.FormattedText;
|
||||||
if (_formatted == null && Element.LineHeight >= 0)
|
if (_formatted == null && Element.LineHeight >= 0)
|
||||||
|
@ -407,10 +432,42 @@ namespace Xamarin.Forms.Platform.MacOS
|
||||||
#else
|
#else
|
||||||
Control.AttributedStringValue = _formatted.ToAttributed(Element, Element.TextColor, Element.HorizontalTextAlignment, Element.LineHeight);
|
Control.AttributedStringValue = _formatted.ToAttributed(Element, Element.TextColor, Element.HorizontalTextAlignment, Element.LineHeight);
|
||||||
#endif
|
#endif
|
||||||
|
_perfectSizeValid = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void UpdateTextHtml()
|
||||||
|
{
|
||||||
|
string text = Element.Text ?? string.Empty;
|
||||||
|
|
||||||
|
#if __MOBILE__
|
||||||
|
var attr = new NSAttributedStringDocumentAttributes
|
||||||
|
{
|
||||||
|
DocumentType = NSDocumentType.HTML
|
||||||
|
};
|
||||||
|
|
||||||
|
NSError nsError = null;
|
||||||
|
|
||||||
|
Control.AttributedText = new NSAttributedString(text, attr, ref nsError);
|
||||||
|
|
||||||
|
#else
|
||||||
|
var attr = new NSAttributedStringDocumentAttributes
|
||||||
|
{
|
||||||
|
DocumentType = NSDocumentType.HTML
|
||||||
|
};
|
||||||
|
|
||||||
|
var htmlData = new NSMutableData();
|
||||||
|
htmlData.SetData(text);
|
||||||
|
|
||||||
|
Control.AttributedStringValue = new NSAttributedString(htmlData, attr, out _);
|
||||||
|
#endif
|
||||||
|
_perfectSizeValid = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
void UpdateFont()
|
void UpdateFont()
|
||||||
{
|
{
|
||||||
|
if (Element?.TextType != TextType.Text)
|
||||||
|
return;
|
||||||
|
|
||||||
if (IsTextFormatted)
|
if (IsTextFormatted)
|
||||||
{
|
{
|
||||||
UpdateFormattedText();
|
UpdateFormattedText();
|
||||||
|
@ -427,6 +484,9 @@ namespace Xamarin.Forms.Platform.MacOS
|
||||||
|
|
||||||
void UpdateTextColor()
|
void UpdateTextColor()
|
||||||
{
|
{
|
||||||
|
if (Element?.TextType != TextType.Text)
|
||||||
|
return;
|
||||||
|
|
||||||
if (IsTextFormatted)
|
if (IsTextFormatted)
|
||||||
{
|
{
|
||||||
UpdateFormattedText();
|
UpdateFormattedText();
|
||||||
|
|
Загрузка…
Ссылка в новой задаче