Retain TextColor and Font properties when using HTML Label on iOS (#10989) fixes #10588

* Ensure that TextColor, and Font apply to HTML Labels on iOS
Fixes #10588

* More tests; handle situations where Forms properties are not set;
This commit is contained in:
E.Z. Hart 2020-06-22 05:55:57 -06:00 коммит произвёл GitHub
Родитель b846bb079e
Коммит 2a6f69df24
Не найден ключ, соответствующий данной подписи
Идентификатор ключа GPG: 4AEE18F83AFDEB23
5 изменённых файлов: 161 добавлений и 25 удалений

Просмотреть файл

@ -64,23 +64,7 @@ namespace Xamarin.Forms.Platform.iOS.UnitTests
return pixel; return pixel;
} }
static bool ARGBEquivalent(UIColor color1, UIColor color2)
{
color1.GetRGBA(out nfloat red1, out nfloat green1, out nfloat blue1, out nfloat alpha1);
color2.GetRGBA(out nfloat red2, out nfloat green2, out nfloat blue2, out nfloat alpha2);
const double tolerance = 0.000001;
return Equal(red1, red2, tolerance)
&& Equal(green1, green2, tolerance)
&& Equal(blue1, blue2, tolerance)
&& Equal(alpha1, alpha2, tolerance);
}
static bool Equal(nfloat v1, nfloat v2, double tolerance)
{
return Math.Abs(v1 - v2) <= tolerance;
}
public static UIImage AssertColorAtPoint(this UIImage bitmap, UIColor expectedColor, int x, int y) public static UIImage AssertColorAtPoint(this UIImage bitmap, UIColor expectedColor, int x, int y)
{ {
@ -88,12 +72,12 @@ namespace Xamarin.Forms.Platform.iOS.UnitTests
{ {
var cap = bitmap.ColorAtPoint(x, y); var cap = bitmap.ColorAtPoint(x, y);
if (!ARGBEquivalent(cap, expectedColor)) if (!ColorComparison.ARGBEquivalent(cap, expectedColor))
{ {
System.Diagnostics.Debug.WriteLine("Here"); System.Diagnostics.Debug.WriteLine("Here");
} }
Assert.That(cap, Is.EqualTo(expectedColor).Using<UIColor>(ARGBEquivalent), Assert.That(cap, Is.EqualTo(expectedColor).Using<UIColor>(ColorComparison.ARGBEquivalent),
() => bitmap.CreateColorAtPointError(expectedColor, x, y)); () => bitmap.CreateColorAtPointError(expectedColor, x, y));
return bitmap; return bitmap;

Просмотреть файл

@ -0,0 +1,26 @@
using System;
using UIKit;
namespace Xamarin.Forms.Platform.iOS.UnitTests
{
internal static class ColorComparison
{
public static bool ARGBEquivalent(UIColor color1, UIColor color2)
{
color1.GetRGBA(out nfloat red1, out nfloat green1, out nfloat blue1, out nfloat alpha1);
color2.GetRGBA(out nfloat red2, out nfloat green2, out nfloat blue2, out nfloat alpha2);
const double tolerance = 0.000001;
return Equal(red1, red2, tolerance)
&& Equal(green1, green2, tolerance)
&& Equal(blue1, blue2, tolerance)
&& Equal(alpha1, alpha2, tolerance);
}
static bool Equal(nfloat v1, nfloat v2, double tolerance)
{
return Math.Abs(v1 - v2) <= tolerance;
}
}
}

Просмотреть файл

@ -0,0 +1,86 @@
using System;
using System.Threading.Tasks;
using NUnit.Framework;
using UIKit;
namespace Xamarin.Forms.Platform.iOS.UnitTests
{
[TestFixture]
public class HtmlLabelTests : PlatformTestFixture
{
[Test, Category("Text"), Category("Label"), Category("Color")]
[Description("Label text color should apply in HTML mode")]
public async Task LabelTextColorAppliesToHtml()
{
var label = new Label { TextColor = Color.Red, Text = "<p>Hello</p>", TextType = TextType.Html };
var expected = Color.Red.ToUIColor();
var actual = await GetControlProperty(label, uiLabel => uiLabel.TextColor);
Assert.That(actual, Is.EqualTo(expected));
}
[Test, Category("Text"), Category("Label"), Category("Color")]
[Description("If Label does not specify a TextColor, HTML colors should work")]
public async Task LabelDefaultTextColorDefersToHtml()
{
var label = new Label { Text = "<p style='color:blue;font-size:72pt'>Hello</p>", TextType = TextType.Html,
VerticalOptions = LayoutOptions.Center };
var expected = Color.Blue.ToUIColor();
var actual = await GetControlProperty(label, uiLabel => uiLabel.TextColor);
Assert.That(actual, Is.EqualTo(expected).Using<UIColor>(ColorComparison.ARGBEquivalent));
}
[Test, Category("Text"), Category("Label"), Category("Color")]
[Description("If Label specifies a TextColor, it should override HTML colors")]
public async Task LabelTextColorOverridesHtmlColors()
{
var label = new Label { Text = "<p style='color:blue;'>Hello</p>", TextType = TextType.Html, TextColor = Color.Red };
var expected = Color.Red.ToUIColor();
var actual = await GetControlProperty(label, uiLabel => uiLabel.TextColor);
Assert.That(actual, Is.EqualTo(expected));
}
[Test, Category("Text"), Category("Label"), Category("Color")]
[Description("Label background color should apply in HTML mode")]
public async Task LabelBackgroundColorAppliesToHtml()
{
var label = new Label { BackgroundColor = Color.Red, Text = "<p>Hello</p>", TextType = TextType.Html };
var expected = Color.Red.ToUIColor();
var actual = await GetRendererProperty(label, r => r.NativeView.BackgroundColor);
Assert.That(actual, Is.EqualTo(expected));
}
[Test, Category("Text"), Category("Label"), Category("Font")]
[Description("Label Font should apply in HTML mode")]
public async Task LabelFontAppliesToHtml()
{
var label = new Label { FontFamily = "MarkerFelt-Thin", FontSize = 24, FontAttributes = FontAttributes.Italic,
Text = "<p>Hello</p>", TextType = TextType.Html };
var expectedFontFamily = label.FontFamily;
var expectedFontSize = (System.nfloat)label.FontSize;
var actualFont = await GetControlProperty(label, uiLabel => uiLabel.Font);
Assert.That(actualFont.FontDescriptor.SymbolicTraits & UIFontDescriptorSymbolicTraits.Italic, Is.Not.Zero);
Assert.That(actualFont.Name, Is.EqualTo(expectedFontFamily));
Assert.That(actualFont.PointSize, Is.EqualTo(expectedFontSize));
}
[Test, Category("Text"), Category("Label"), Category("Font")]
[Description("If Label Font is not set HTML fonts should apply")]
public async Task LabelFontDefaultDefersToHtml()
{
var label = new Label
{
Text = "<p style='font-size:3em'>Hello</p>",
TextType = TextType.Html
};
nfloat expectedFontSize = 36; // 12pt * 3em
var actualFont = await GetControlProperty(label, uiLabel => uiLabel.Font);
Assert.That(actualFont.PointSize, Is.EqualTo(expectedFontSize));
}
}
}

Просмотреть файл

@ -55,9 +55,11 @@
</Compile> </Compile>
<Compile Include="AssertionExtensions.cs" /> <Compile Include="AssertionExtensions.cs" />
<Compile Include="BackgroundColorTests.cs" /> <Compile Include="BackgroundColorTests.cs" />
<Compile Include="ColorComparison.cs" />
<Compile Include="CornerRadiusTests.cs" /> <Compile Include="CornerRadiusTests.cs" />
<Compile Include="EmbeddingTests.cs" /> <Compile Include="EmbeddingTests.cs" />
<Compile Include="FlowDirectionTests.cs" /> <Compile Include="FlowDirectionTests.cs" />
<Compile Include="HtmlLabelTests.cs" />
<Compile Include="ImageButtonTests.cs" /> <Compile Include="ImageButtonTests.cs" />
<Compile Include="IsEnabledTests.cs" /> <Compile Include="IsEnabledTests.cs" />
<Compile Include="IsVisibleTests.cs" /> <Compile Include="IsVisibleTests.cs" />

Просмотреть файл

@ -474,6 +474,10 @@ namespace Xamarin.Forms.Platform.MacOS
Control.AttributedStringValue = new NSAttributedString(htmlData, attr, out _); Control.AttributedStringValue = new NSAttributedString(htmlData, attr, out _);
#endif #endif
_perfectSizeValid = false; _perfectSizeValid = false;
// Setting AttributedText will reset style-related properties, so we'll need to update them again
UpdateTextColor();
UpdateFont();
} }
protected virtual NSAttributedStringDocumentAttributes GetNSAttributedStringDocumentAttributes() protected virtual NSAttributedStringDocumentAttributes GetNSAttributedStringDocumentAttributes()
@ -485,10 +489,32 @@ namespace Xamarin.Forms.Platform.MacOS
}; };
} }
static bool FontIsDefault(Label label)
{
if (label.IsSet(Label.FontAttributesProperty))
{
return false;
}
if (label.IsSet(Label.FontFamilyProperty))
{
return false;
}
if (label.IsSet(Label.FontSizeProperty))
{
return false;
}
return true;
}
void UpdateFont() void UpdateFont()
{ {
if (Element?.TextType != TextType.Text) if(Element == null)
{
return; return;
}
if (IsTextFormatted) if (IsTextFormatted)
{ {
@ -496,6 +522,13 @@ namespace Xamarin.Forms.Platform.MacOS
return; return;
} }
if (Element.TextType == TextType.Html && FontIsDefault(Element))
{
// If no explicit font properties have been specified and we're display HTML,
// let the HTML determine the typeface
return;
}
#if __MOBILE__ #if __MOBILE__
Control.Font = Element.ToUIFont(); Control.Font = Element.ToUIFont();
#else #else
@ -506,9 +539,6 @@ namespace Xamarin.Forms.Platform.MacOS
void UpdateTextColor() void UpdateTextColor()
{ {
if (Element?.TextType != TextType.Text)
return;
if (IsTextFormatted) if (IsTextFormatted)
{ {
UpdateFormattedText(); UpdateFormattedText();
@ -517,9 +547,16 @@ namespace Xamarin.Forms.Platform.MacOS
var textColor = (Color)Element.GetValue(Label.TextColorProperty); var textColor = (Color)Element.GetValue(Label.TextColorProperty);
// default value of color documented to be black in iOS docs if (textColor.IsDefault && Element.TextType == TextType.Html)
{
// If no explicit text color has been specified and we're displaying HTML,
// let the HTML determine the colors
return;
}
// default value of color documented to be black in iOS docs
#if __MOBILE__ #if __MOBILE__
Control.TextColor = textColor.ToUIColor(ColorExtensions.LabelColor); Control.TextColor = textColor.ToUIColor(ColorExtensions.LabelColor);
#else #else
var alignment = Element.HorizontalTextAlignment.ToNativeTextAlignment(((IVisualElementController)Element).EffectiveFlowDirection); var alignment = Element.HorizontalTextAlignment.ToNativeTextAlignment(((IVisualElementController)Element).EffectiveFlowDirection);
var textWithColor = new NSAttributedString(Element.Text ?? "", font: Element.ToNSFont(), foregroundColor: textColor.ToNSColor(ColorExtensions.Black), paragraphStyle: new NSMutableParagraphStyle() { Alignment = alignment }); var textWithColor = new NSAttributedString(Element.Text ?? "", font: Element.ToNSFont(), foregroundColor: textColor.ToNSColor(ColorExtensions.Black), paragraphStyle: new NSMutableParagraphStyle() { Alignment = alignment });
@ -528,6 +565,7 @@ namespace Xamarin.Forms.Platform.MacOS
#endif #endif
UpdateLayout(); UpdateLayout();
} }
void UpdateLayout() void UpdateLayout()
{ {
#if __MOBILE__ #if __MOBILE__