Skip to content
This repository has been archived by the owner on May 1, 2024. It is now read-only.

Commit

Permalink
Make Label display HTML from a string (#4527)
Browse files Browse the repository at this point in the history
* 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
  • Loading branch information
jfversluis committed Aug 28, 2019
1 parent c0a681e commit 938a840
Show file tree
Hide file tree
Showing 13 changed files with 414 additions and 18 deletions.
@@ -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
}
}
Expand Up @@ -1029,6 +1029,7 @@
<Compile Include="$(MSBuildThisFileDirectory)Issue6738.cs" />
<Compile Include="$(MSBuildThisFileDirectory)GitHub6926.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Issue5503.cs" />
<Compile Include="$(MSBuildThisFileDirectory)LabelTextType.cs" />
</ItemGroup>
<ItemGroup>
<EmbeddedResource Include="$(MSBuildThisFileDirectory)Bugzilla22229.xaml">
Expand Down
37 changes: 37 additions & 0 deletions Xamarin.Forms.Controls/CoreGalleryPages/LabelCoreGalleryPage.cs
Expand Up @@ -236,6 +236,40 @@ protected override void Build (StackLayout stackLayout)
Padding = new Thickness(40, 20)
}
);

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&nbsp;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 (namedSizeMediumItalicContainer);
Expand Down Expand Up @@ -272,6 +306,9 @@ protected override void Build (StackLayout stackLayout)
Add (maxlinesTailTruncContainer);
Add (maxlinesWordWrapContainer);
Add(paddingContainer);
Add (htmlLabelContainer);
Add (htmlLabelMultipleLinesContainer);
Add (toggleHtmlPlainTextLabelContainer);
}
}
}
9 changes: 9 additions & 0 deletions Xamarin.Forms.Core/Label.cs
Expand Up @@ -89,6 +89,9 @@ public class Label : View, IFontElement, ITextElement, ITextAlignmentElement, IL
});

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;

Expand Down Expand Up @@ -212,6 +215,12 @@ public Thickness Padding
get { return (Thickness)GetValue(PaddingProperty); }
set { SetValue(PaddingProperty, value); }
}

public TextType TextType
{
get => (TextType)GetValue(TextTypeProperty);
set => SetValue(TextTypeProperty, value);
}

double IFontElement.FontSizeDefaultValueCreator() =>
Device.GetNamedSize(NamedSize.Default, (Label)this);
Expand Down
8 changes: 8 additions & 0 deletions Xamarin.Forms.Core/TextType.cs
@@ -0,0 +1,8 @@
namespace Xamarin.Forms
{
public enum TextType
{
Text,
Html
}
}
3 changes: 2 additions & 1 deletion Xamarin.Forms.CustomAttributes/TestAttributes.cs
Expand Up @@ -635,7 +635,8 @@ public enum Label
VerticalTextAlignmentStart,
VerticalTextAlignmentCenter,
VerticalTextAlignmentEnd,
MaxLines
MaxLines,
TextType
}

public enum MasterDetailPage
Expand Down
24 changes: 21 additions & 3 deletions Xamarin.Forms.Platform.Android/FastRenderers/LabelRenderer.cs
Expand Up @@ -251,6 +251,7 @@ protected virtual void OnElementChanged(ElementChangedEventArgs<Label> e)
UpdateGravity();
if (e.OldElement?.MaxLines != e.NewElement.MaxLines)
UpdateMaxLines();

UpdatePadding();

ElevationHelper.SetElevation(this, e.NewElement);
Expand All @@ -263,7 +264,8 @@ protected virtual void OnElementPropertyChanged(object sender, PropertyChangedEv

if (e.PropertyName == Label.HorizontalTextAlignmentProperty.PropertyName || e.PropertyName == Label.VerticalTextAlignmentProperty.PropertyName)
UpdateGravity();
else if (e.PropertyName == Label.TextColorProperty.PropertyName)
else if (e.PropertyName == Label.TextColorProperty.PropertyName ||
e.PropertyName == Label.TextTypeProperty.PropertyName)
UpdateText();
else if (e.PropertyName == Label.FontProperty.PropertyName)
UpdateText();
Expand Down Expand Up @@ -380,7 +382,23 @@ void UpdateText()
SetTextColor(_labelTextColorDefault);
_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();
UpdateFont();

Expand Down Expand Up @@ -416,4 +434,4 @@ void UpdatePadding()
_lastSizeRequest = null;
}
}
}
}
11 changes: 11 additions & 0 deletions Xamarin.Forms.Platform.Android/Forms.cs
Expand Up @@ -56,6 +56,7 @@ public static class Forms
static BuildVersionCodes? s_sdkInt;
static bool? s_isLollipopOrNewer;
static bool? s_isMarshmallowOrNewer;
static bool? s_isNougatOrNewer;

[Obsolete("Context is obsolete as of version 2.5. Please use a local context instead.")]
[EditorBrowsable(EditorBrowsableState.Never)]
Expand Down Expand Up @@ -98,6 +99,16 @@ internal static bool IsMarshmallowOrNewer
}
}

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)
{
float size = 50;
Expand Down
26 changes: 21 additions & 5 deletions Xamarin.Forms.Platform.Android/Renderers/LabelRenderer.cs
Expand Up @@ -135,7 +135,6 @@ protected override void OnElementChanged(ElementChangedEventArgs<Label> e)
UpdateMaxLines();
if (e.OldElement.CharacterSpacing != e.NewElement.CharacterSpacing)
UpdateCharacterSpacing();

}
UpdateTextDecorations();
UpdatePadding();
Expand All @@ -158,13 +157,13 @@ protected override void OnElementPropertyChanged(object sender, PropertyChangedE
UpdateLineBreakMode();
else if (e.PropertyName == Label.TextDecorationsProperty.PropertyName)
UpdateTextDecorations();
else if (e.PropertyName == Label.TextProperty.PropertyName || e.PropertyName == Label.FormattedTextProperty.PropertyName)
else if (e.IsOneOf(Label.TextProperty, Label.FormattedTextProperty, Label.TextTypeProperty))
UpdateText();
else if (e.PropertyName == Label.LineHeightProperty.PropertyName)
UpdateLineHeight();
else if (e.PropertyName == Label.MaxLinesProperty.PropertyName)
UpdateMaxLines();
else if (e.PropertyName == ImageButton.PaddingProperty.PropertyName)
else if (e.PropertyName == Label.PaddingProperty.PropertyName)
UpdatePadding();
}

Expand Down Expand Up @@ -242,7 +241,6 @@ void UpdateCharacterSpacing()
}
}


void UpdateLineHeight()
{
_lastSizeRequest = null;
Expand Down Expand Up @@ -274,7 +272,25 @@ void UpdateText()
_view.SetTextColor(_labelTextColorDefault);
_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();
UpdateFont();

Expand Down

0 comments on commit 938a840

Please sign in to comment.