[Enhancement] Allow underline and strikethrough text decorations on labels and spans (#2221)

* Fixes #1632

* Allow underline and strikethrought text decorations on labels and spans

* revert some files

* pr feedback adjustments

* remove docs

* rename interface

* reorder enum

* clean up whitespace

* adjust tizen renderer

* add gallery demo for setting both underline and strike

* allow multiple values of enum to be set in xaml/css

* use normal null check

* use nameof

* include paragraph style

* tab alignment

* rebase from upstream

* pass control to update method on UWP

* correct text decorations type converter

* reset run text instead of label text on UWP when spans are used

* add tests for text decoration converter
This commit is contained in:
Alan Grgic 2018-07-20 18:57:11 -05:00 коммит произвёл Shane Neuville
Родитель fd733037a4
Коммит 97d2f30f6b
19 изменённых файлов: 361 добавлений и 18 удалений

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

@ -26,6 +26,14 @@ namespace Xamarin.Forms.Controls
var namedSizeMediumItalicContainer = new ViewContainer<Label> (Test.Label.FontAttributesItalic, new Label { Text = "Medium Italic Font", Font = Font.SystemFontOfSize (NamedSize.Medium, FontAttributes.Italic) });
#pragma warning restore 618
#pragma warning disable 618
var namedSizeMediumUnderlineContainer = new ViewContainer<Label>(Test.Label.TextDecorationUnderline, new Label { Text = "Medium Underlined Font", Font = Font.SystemFontOfSize(NamedSize.Medium), TextDecorations = TextDecorations.Underline });
#pragma warning restore 618
#pragma warning disable 618
var namedSizeMediumStrikeContainer = new ViewContainer<Label>(Test.Label.TextDecorationStrike, new Label { Text = "Medium StrikeThrough Font", Font = Font.SystemFontOfSize(NamedSize.Medium), TextDecorations = TextDecorations.Strikethrough });
#pragma warning restore 618
#pragma warning disable 618
var namedSizeLargeContainer = new ViewContainer<Label> (Test.Label.FontNamedSizeLarge, new Label { Text = "Large Font", Font = Font.SystemFontOfSize (NamedSize.Large) });
#pragma warning restore 618
@ -151,6 +159,8 @@ namespace Xamarin.Forms.Controls
Add (namedSizeMediumBoldContainer);
Add (namedSizeMediumItalicContainer);
Add (namedSizeMediumUnderlineContainer);
Add (namedSizeMediumStrikeContainer);
Add (namedSizeLargeContainer);
Add (namedSizeMediumContainer);
Add (namedSizeMicroContainer);

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

@ -29,6 +29,14 @@ namespace Xamarin.Forms.Controls
var italicfont = new Label { Text = "Custom Italic Font" };
var boldfont = new Label { Text = "Custom Bold Font" };
var bolditalicfont = new Label { Text = "Custom Bold Italic Font" };
var toggleUnderline = new Label { Text = "Tap to toggle Underline", TextDecorations = TextDecorations.Underline };
toggleUnderline.GestureRecognizers.Add(new TapGestureRecognizer { Command = new Command(()=> { toggleUnderline.TextDecorations ^= TextDecorations.Underline; }) });
var toggleStrike = new Label { Text = "Tap to toggle StrikeThrough", TextDecorations = TextDecorations.Strikethrough };
toggleStrike.GestureRecognizers.Add(new TapGestureRecognizer { Command = new Command(() => { toggleStrike.TextDecorations ^= TextDecorations.Strikethrough; }) });
var toggleBoth = new Label { Text = "Tap to toggle both", TextDecorations = TextDecorations.Strikethrough | TextDecorations.Underline };
toggleBoth.GestureRecognizers.Add(new TapGestureRecognizer { Command = new Command(() => { toggleBoth.TextDecorations ^= TextDecorations.Strikethrough;
toggleBoth.TextDecorations ^= TextDecorations.Underline;
}) });
var huge = new Label {
Text = "This is the label that never ends, yes it go on and on my friend. " +
"Some people started catting it not knowing what it was, and they'll continue catting it forever just because...",
@ -39,10 +47,13 @@ namespace Xamarin.Forms.Controls
#pragma warning disable 618
new Span {Text="FormattedStrings ", TextColor=Color.Blue, BackgroundColor = Color.Yellow, Font = Font.BoldSystemFontOfSize (NamedSize.Large)},
#pragma warning restore 618
new Span {Text="are ", TextColor=Color.Red, BackgroundColor = Color.Gray},
new Span {Text="not pretty!", TextColor = Color.Green,},
}
} };
var underlineSpan = new Span { Text = "are ", TextColor = Color.Red, BackgroundColor = Color.Gray, TextDecorations = TextDecorations.Underline };
var strikeSpan = new Span { Text = "not pretty!", TextColor = Color.Green, TextDecorations = TextDecorations.Strikethrough };
formatted.FormattedText.Spans.Add(underlineSpan);
formatted.FormattedText.Spans.Add(strikeSpan);
var missingfont = new Label { Text = "Missing font: use default" };
#pragma warning disable 618
@ -148,6 +159,9 @@ namespace Xamarin.Forms.Controls
bold,
italic,
bolditalic,
toggleUnderline,
toggleStrike,
toggleBoth,
customFont,
italicfont,
boldfont,

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

@ -0,0 +1,28 @@
using System.Globalization;
using NUnit.Framework;
namespace Xamarin.Forms.Core.UnitTests
{
[TestFixture]
public class TextDecorationUnitTests : BaseTestFixture
{
[Test]
public void TestTextDecorationConverter()
{
var converter = new TextDecorationConverter();
TextDecorations both = TextDecorations.Strikethrough;
both |= TextDecorations.Underline;
Assert.True(converter.CanConvertFrom(typeof(string)));
Assert.AreEqual(TextDecorations.Strikethrough, converter.ConvertFromInvariantString("strikethrough"));
Assert.AreEqual(TextDecorations.Underline, converter.ConvertFromInvariantString("underline"));
Assert.AreEqual(TextDecorations.Strikethrough, converter.ConvertFromInvariantString("line-through"));
Assert.AreEqual(TextDecorations.None, converter.ConvertFromInvariantString("none"));
Assert.AreEqual(both, converter.ConvertFromInvariantString("strikethrough underline"));
Assert.AreEqual(both, converter.ConvertFromInvariantString("underline strikethrough"));
Assert.AreEqual(both, converter.ConvertFromInvariantString("underline line-through"));
Assert.AreEqual(both, converter.ConvertFromInvariantString("line-through underline"));
}
}
}

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

@ -1,4 +1,4 @@
<?xml version="1.0" encoding="utf-8"?>
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="12.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
<PropertyGroup>
@ -149,6 +149,7 @@
<Compile Include="TapGestureRecognizerTests.cs" />
<Compile Include="TemplatedItemsListTests.cs" />
<Compile Include="TextCellTests.cs" />
<Compile Include="TextDecorationUnitTests.cs" />
<Compile Include="ThicknessTests.cs" />
<Compile Include="TimePickerUnitTest.cs" />
<Compile Include="ToolbarItemTests.cs" />
@ -228,4 +229,4 @@
<LogicalName>Images/crimson.jpg</LogicalName>
</EmbeddedResource>
</ItemGroup>
</Project>
</Project>

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

@ -0,0 +1,49 @@
using System;
using System.Collections.Generic;
using System.Text;
namespace Xamarin.Forms
{
[Flags]
[TypeConverter(typeof(TextDecorationConverter))]
public enum TextDecorations
{
None = 0,
Underline = 1 << 0,
Strikethrough = 1 << 1,
}
static class DecorableTextElement
{
public static readonly BindableProperty TextDecorationsProperty = BindableProperty.Create(nameof(IDecorableTextElement.TextDecorations), typeof(TextDecorations), typeof(IDecorableTextElement), TextDecorations.None);
}
[Xaml.TypeConversion(typeof(TextDecorations))]
public class TextDecorationConverter : TypeConverter
{
public override object ConvertFromInvariantString(string value)
{
TextDecorations result = TextDecorations.None;
if (value == null)
throw new InvalidOperationException(string.Format("Cannot convert \"{0}\" into {1}", value, typeof(TextDecorations)));
var valueArr = value.Split(',');
if (valueArr.Length <= 1)
valueArr = value.Split(' ');
foreach (var item in valueArr)
{
if (Enum.TryParse(item.Trim(), true, out TextDecorations textDecorations))
result |= textDecorations;
else if (item.Equals("line-through", StringComparison.OrdinalIgnoreCase))
result |= TextDecorations.Strikethrough;
else
throw new InvalidOperationException(string.Format("Cannot convert \"{0}\" into {1}", item, typeof(TextDecorations)));
}
return result;
}
}
}

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

@ -0,0 +1,11 @@
using System;
using System.Collections.Generic;
using System.Text;
namespace Xamarin.Forms
{
public interface IDecorableTextElement
{
TextDecorations TextDecorations { get; set; }
}
}

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

@ -11,7 +11,7 @@ namespace Xamarin.Forms
{
[ContentProperty("Text")]
[RenderWith(typeof(_LabelRenderer))]
public class Label : View, IFontElement, ITextElement, ITextAlignmentElement, ILineHeightElement, IElementConfiguration<Label>
public class Label : View, IFontElement, ITextElement, ITextAlignmentElement, ILineHeightElement, IElementConfiguration<Label>, IDecorableTextElement
{
public static readonly BindableProperty HorizontalTextAlignmentProperty = TextAlignmentElement.HorizontalTextAlignmentProperty;
@ -36,6 +36,8 @@ namespace Xamarin.Forms
public static readonly BindableProperty FontAttributesProperty = FontElement.FontAttributesProperty;
public static readonly BindableProperty TextDecorationsProperty = DecorableTextElement.TextDecorationsProperty;
public static readonly BindableProperty FormattedTextProperty = BindableProperty.Create(nameof(FormattedText), typeof(FormattedString), typeof(Label), default(FormattedString),
propertyChanging: (bindable, oldvalue, newvalue) =>
{
@ -155,6 +157,12 @@ namespace Xamarin.Forms
set { SetValue(FontAttributesProperty, value); }
}
public TextDecorations TextDecorations
{
get { return (TextDecorations)GetValue(TextDecorationsProperty); }
set { SetValue(TextDecorationsProperty, value); }
}
public string FontFamily
{
get { return (string)GetValue(FontFamilyProperty); }

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

@ -60,6 +60,7 @@ using Xamarin.Forms.StyleSheets;
[assembly: StyleProperty("padding-right", typeof(IPaddingElement), nameof(PaddingElement.PaddingRightProperty), PropertyOwnerType = typeof(PaddingElement))]
[assembly: StyleProperty("padding-bottom", typeof(IPaddingElement), nameof(PaddingElement.PaddingBottomProperty), PropertyOwnerType = typeof(PaddingElement))]
[assembly: StyleProperty("text-align", typeof(ITextAlignmentElement), nameof(TextAlignmentElement.HorizontalTextAlignmentProperty), Inherited = true)]
[assembly: StyleProperty("text-decoration", typeof(IDecorableTextElement), nameof(DecorableTextElement.TextDecorationsProperty))]
[assembly: StyleProperty("visibility", typeof(VisualElement), nameof(VisualElement.IsVisibleProperty), Inherited = true)]
[assembly: StyleProperty("width", typeof(VisualElement), nameof(VisualElement.WidthRequestProperty))]
[assembly: StyleProperty("line-height", typeof(ILineHeightElement), nameof(LineHeightElement.LineHeightProperty), Inherited = true)]

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

@ -4,7 +4,7 @@ using Xamarin.Forms.Internals;
namespace Xamarin.Forms
{
[ContentProperty("Text")]
public sealed class Span : GestureElement, IFontElement, ITextElement, ILineHeightElement
public sealed class Span : GestureElement, IFontElement, ITextElement, ILineHeightElement, IDecorableTextElement
{
internal readonly MergedStyle _mergedStyle;
@ -16,6 +16,8 @@ namespace Xamarin.Forms
public static readonly BindableProperty StyleProperty = BindableProperty.Create(nameof(Style), typeof(Style), typeof(Span), default(Style),
propertyChanged: (bindable, oldvalue, newvalue) => ((Span)bindable)._mergedStyle.Style = (Style)newvalue, defaultBindingMode: BindingMode.OneTime);
public static readonly BindableProperty TextDecorationsProperty = DecorableTextElement.TextDecorationsProperty;
public Style Style
{
get { return (Style)GetValue(StyleProperty); }
@ -95,6 +97,12 @@ namespace Xamarin.Forms
set { SetValue(FontElement.FontSizeProperty, value); }
}
public TextDecorations TextDecorations
{
get { return (TextDecorations)GetValue(TextDecorationsProperty); }
set { SetValue(TextDecorationsProperty, value); }
}
public double LineHeight {
get { return (double)GetValue(LineHeightElement.LineHeightProperty); }
set { SetValue(LineHeightElement.LineHeightProperty, value); }

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

@ -582,6 +582,8 @@ namespace Xamarin.Forms.CustomAttributes
FormattedText,
FontAttibutesBold,
FontAttributesItalic,
TextDecorationUnderline,
TextDecorationStrike,
FontNamedSizeMicro,
FontNamedSizeSmall,
FontNamedSizeMedium,

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

@ -280,6 +280,24 @@ namespace Xamarin.Forms.Platform.Android.FastRenderers
}
}
void UpdateTextDecorations()
{
if (!Element.IsSet(Label.TextDecorationsProperty))
return;
var textDecorations = Element.TextDecorations;
if ((textDecorations & TextDecorations.Strikethrough) == 0)
PaintFlags &= ~PaintFlags.StrikeThruText;
else
PaintFlags |= PaintFlags.StrikeThruText;
if ((textDecorations & TextDecorations.Underline) == 0)
PaintFlags &= ~PaintFlags.UnderlineText;
else
PaintFlags |= PaintFlags.UnderlineText;
}
void UpdateGravity()
{
Label label = Element;

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

@ -62,6 +62,8 @@ namespace Xamarin.Forms.Platform.Android
#pragma warning restore 618
else
spannable.SetSpan(new FontSpan(defaultFont, view), start, end, SpanTypes.InclusiveInclusive);
if (span.IsSet(Span.TextDecorationsProperty))
spannable.SetSpan(new TextDecorationSpan(span), start, end, SpanTypes.InclusiveInclusive);
}
return spannable;
}
@ -95,6 +97,34 @@ namespace Xamarin.Forms.Platform.Android
paint.TextSize = TypedValue.ApplyDimension(ComplexUnitType.Sp, value, TextView.Resources.DisplayMetrics);
}
}
class TextDecorationSpan : MetricAffectingSpan
{
public TextDecorationSpan(Span span)
{
Span = span;
}
public Span Span { get; }
public override void UpdateDrawState(TextPaint tp)
{
Apply(tp);
}
public override void UpdateMeasureState(TextPaint p)
{
Apply(p);
}
void Apply(Paint paint)
{
var textDecorations = Span.TextDecorations;
paint.UnderlineText = (textDecorations & TextDecorations.Underline) != 0;
paint.StrikeThruText = (textDecorations & TextDecorations.Strikethrough) != 0;
}
}
class LineHeightSpan : Java.Lang.Object, ILineHeightSpan
{
private double _lineHeight;
@ -114,7 +144,6 @@ namespace Xamarin.Forms.Platform.Android
fm.Ascent = (int) (_ascent * _lineHeight);
fm.Descent = (int) (_descent * _lineHeight);
}
}
}
}

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

@ -118,7 +118,7 @@ namespace Xamarin.Forms.Platform.Android
if (e.OldElement.HorizontalTextAlignment != e.NewElement.HorizontalTextAlignment || e.OldElement.VerticalTextAlignment != e.NewElement.VerticalTextAlignment)
UpdateGravity();
}
UpdateTextDecorations();
_motionEventHelper.UpdateElement(e.NewElement);
}
@ -134,6 +134,8 @@ namespace Xamarin.Forms.Platform.Android
UpdateText();
else if (e.PropertyName == Label.LineBreakModeProperty.PropertyName)
UpdateLineBreakMode();
else if (e.PropertyName == Label.TextDecorationsProperty.PropertyName)
UpdateTextDecorations();
else if (e.PropertyName == Label.TextProperty.PropertyName || e.PropertyName == Label.FormattedTextProperty.PropertyName)
UpdateText();
else if (e.PropertyName == Label.LineHeightProperty.PropertyName)
@ -174,6 +176,24 @@ namespace Xamarin.Forms.Platform.Android
}
}
void UpdateTextDecorations()
{
if (!Element.IsSet(Label.TextDecorationsProperty))
return;
var textDecorations = Element.TextDecorations;
if ((textDecorations & TextDecorations.Strikethrough) == 0)
_view.PaintFlags &= ~PaintFlags.StrikeThruText;
else
_view.PaintFlags |= PaintFlags.StrikeThruText;
if ((textDecorations & TextDecorations.Underline) == 0)
_view.PaintFlags &= ~PaintFlags.UnderlineText;
else
_view.PaintFlags |= PaintFlags.UnderlineText;
}
void UpdateGravity()
{
Label label = Element;

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

@ -19,6 +19,7 @@ namespace Xamarin.Forms.Platform.Tizen
RegisterPropertyHandler(Label.FormattedTextProperty, UpdateFormattedText);
RegisterPropertyHandler(Label.LineHeightProperty, UpdateLineHeight);
RegisterPropertyHandler(Specific.FontWeightProperty, UpdateFontWeight);
RegisterPropertyHandler(Label.TextDecorationsProperty, UpdateTextDecorations);
}
protected override void OnElementChanged(ElementChangedEventArgs<Label> e)
@ -46,6 +47,8 @@ namespace Xamarin.Forms.Platform.Tizen
foreach (var span in formattedString.Spans)
{
var textDecorations = span.TextDecorations;
Native.Span nativeSpan = new Native.Span();
nativeSpan.Text = span.Text;
nativeSpan.FontAttributes = span.FontAttributes;
@ -53,6 +56,8 @@ namespace Xamarin.Forms.Platform.Tizen
nativeSpan.FontSize = span.FontSize;
nativeSpan.ForegroundColor = span.TextColor.ToNative();
nativeSpan.BackgroundColor = span.BackgroundColor.ToNative();
nativeSpan.Underline = (textDecorations & TextDecorations.Underline) != 0;
nativeSpan.Strikethrough = (textDecorations & TextDecorations.Strikethrough) != 0;
nativeSpan.LineHeight = span.LineHeight;
nativeString.Spans.Add(nativeSpan);
}
@ -60,6 +65,15 @@ namespace Xamarin.Forms.Platform.Tizen
return nativeString;
}
void UpdateTextDecorations()
{
Control.BatchBegin();
var textDecorations = Element.TextDecorations;
Control.Strikethrough = (textDecorations & TextDecorations.Strikethrough) != 0;
Control.Underline = (textDecorations & TextDecorations.Underline) != 0;
Control.BatchCommit();
}
void UpdateFormattedText()
{
if (Element.FormattedText != null)

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

@ -25,6 +25,9 @@ namespace Xamarin.Forms.Platform.UWP
run.ApplyFont(span.Font);
#pragma warning restore 618
if (span.IsSet(Span.TextDecorationsProperty))
run.TextDecorations = (Windows.UI.Text.TextDecorations)span.TextDecorations;
return run;
}
}
@ -132,6 +135,7 @@ namespace Xamarin.Forms.Platform.UWP
_isInitiallyDefault = Element.IsDefault();
UpdateText(Control);
UpdateTextDecorations(Control);
UpdateColor(Control);
UpdateAlign(Control);
UpdateFont(Control);
@ -150,6 +154,8 @@ namespace Xamarin.Forms.Platform.UWP
UpdateAlign(Control);
else if (e.PropertyName == Label.FontProperty.PropertyName)
UpdateFont(Control);
else if (e.PropertyName == Label.TextDecorationsProperty.PropertyName)
UpdateTextDecorations(Control);
else if (e.PropertyName == Label.LineBreakModeProperty.PropertyName)
UpdateLineBreakMode(Control);
else if (e.PropertyName == VisualElement.FlowDirectionProperty.PropertyName)
@ -161,6 +167,39 @@ namespace Xamarin.Forms.Platform.UWP
base.OnElementPropertyChanged(sender, e);
}
void UpdateTextDecorations(TextBlock textBlock)
{
if (!Element.IsSet(Label.TextDecorationsProperty))
return;
var elementTextDecorations = Element.TextDecorations;
if ((elementTextDecorations & TextDecorations.Underline) == 0)
textBlock.TextDecorations &= ~Windows.UI.Text.TextDecorations.Underline;
else
textBlock.TextDecorations |= Windows.UI.Text.TextDecorations.Underline;
if ((elementTextDecorations & TextDecorations.Strikethrough) == 0)
textBlock.TextDecorations &= ~Windows.UI.Text.TextDecorations.Strikethrough;
else
textBlock.TextDecorations |= Windows.UI.Text.TextDecorations.Strikethrough;
//TextDecorations are not updated in the UI until the text changes
if (textBlock.Inlines != null && textBlock.Inlines.Count > 0)
{
for (var i = 0; i < textBlock.Inlines.Count; i++)
{
var run = (Run)textBlock.Inlines[i];
run.Text = run.Text;
}
}
else
{
textBlock.Text = textBlock.Text;
}
}
void UpdateAlign(TextBlock textBlock)
{
_perfectSizeValid = false;

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

@ -29,7 +29,17 @@ namespace Xamarin.Forms.Platform.WPF
#pragma warning disable 618
run.ApplyFont(span.Font);
#pragma warning restore 618
if (!span.IsSet(Span.TextDecorationsProperty))
return run;
var textDecorations = span.TextDecorations;
if ((textDecorations & TextDecorations.Underline) != 0)
run.TextDecorations.Add(System.Windows.TextDecorations.Underline);
if ((textDecorations & TextDecorations.Strikethrough) != 0)
run.TextDecorations.Add(System.Windows.TextDecorations.Strikethrough);
return run;
}
}

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

@ -25,6 +25,7 @@ namespace Xamarin.Forms.Platform.WPF
// Update control property
UpdateText();
UpdateTextDecorations();
UpdateColor();
UpdateAlign();
UpdateFont();
@ -47,6 +48,8 @@ namespace Xamarin.Forms.Platform.WPF
if (e.PropertyName == Label.TextProperty.PropertyName || e.PropertyName == Label.FormattedTextProperty.PropertyName)
UpdateText();
else if (e.PropertyName == Label.TextDecorationsProperty.PropertyName)
UpdateTextDecorations();
else if (e.PropertyName == Label.TextColorProperty.PropertyName)
UpdateColor();
else if (e.PropertyName == Label.HorizontalTextAlignmentProperty.PropertyName || e.PropertyName == Label.VerticalTextAlignmentProperty.PropertyName)
@ -62,6 +65,29 @@ namespace Xamarin.Forms.Platform.WPF
Control.UpdateDependencyColor(TextBlock.BackgroundProperty, Element.BackgroundColor);
}
void UpdateTextDecorations()
{
if (!Element.IsSet(Label.TextDecorationsProperty))
return;
var textDecorations = Element.TextDecorations;
var newTextDecorations = new System.Windows.TextDecorationCollection(Control.TextDecorations);
if ((textDecorations & TextDecorations.Underline) == 0)
newTextDecorations.TryRemove(System.Windows.TextDecorations.Underline, out newTextDecorations);
else
newTextDecorations.Add(System.Windows.TextDecorations.Underline);
if ((textDecorations & TextDecorations.Strikethrough) == 0)
newTextDecorations.TryRemove(System.Windows.TextDecorations.Strikethrough, out newTextDecorations);
else
newTextDecorations.Add(System.Windows.TextDecorations.Strikethrough);
Control.TextDecorations = newTextDecorations;
}
void UpdateAlign()
{
if (Control == null)

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

@ -76,20 +76,13 @@ namespace Xamarin.Forms.Platform.MacOS
targetFont = ((IFontElement)owner).ToUIFont();
else
targetFont = span.ToUIFont();
var fgcolor = span.TextColor;
if (fgcolor.IsDefault)
fgcolor = defaultForegroundColor;
if (fgcolor.IsDefault)
fgcolor = Color.Black; // as defined by apple docs
return new NSAttributedString(text, targetFont, fgcolor.ToUIColor(), span.BackgroundColor.ToUIColor(), null, style);
#else
NSFont targetFont;
if (span.IsDefault())
targetFont = ((IFontElement)owner).ToNSFont();
else
targetFont = span.ToNSFont();
#endif
var fgcolor = span.TextColor;
if (fgcolor.IsDefault)
@ -97,9 +90,32 @@ namespace Xamarin.Forms.Platform.MacOS
if (fgcolor.IsDefault)
fgcolor = Color.Black; // as defined by apple docs
return new NSAttributedString(text, targetFont, fgcolor.ToNSColor(), span.BackgroundColor.ToNSColor(),
null, null, null, NSUnderlineStyle.None, NSUnderlineStyle.None, style);
#if __MOBILE__
UIColor spanFgColor;
UIColor spanBgColor;
spanFgColor = fgcolor.ToUIColor();
spanBgColor = span.BackgroundColor.ToUIColor();
#else
NSColor spanFgColor;
NSColor spanBgColor;
spanFgColor = fgcolor.ToNSColor();
spanBgColor = span.BackgroundColor.ToNSColor();
#endif
bool hasUnderline = false;
bool hasStrikethrough = false;
if (span.IsSet(Span.TextDecorationsProperty))
{
var textDecorations = span.TextDecorations;
hasUnderline = (textDecorations & TextDecorations.Underline) != 0;
hasStrikethrough = (textDecorations & TextDecorations.Strikethrough) != 0;
}
var attrString = new NSAttributedString(text, targetFont, spanFgColor, spanBgColor,
underlineStyle: hasUnderline ? NSUnderlineStyle.Single : NSUnderlineStyle.None,
strikethroughStyle: hasStrikethrough ? NSUnderlineStyle.Single : NSUnderlineStyle.None, paragraphStyle: style);
return attrString;
}
internal static NSAttributedString ToAttributed(this FormattedString formattedString, Element owner,

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

@ -2,6 +2,7 @@ using System;
using System.ComponentModel;
using RectangleF = CoreGraphics.CGRect;
using SizeF = CoreGraphics.CGSize;
using Foundation;
#if __MOBILE__
using UIKit;
@ -129,6 +130,7 @@ namespace Xamarin.Forms.Platform.MacOS
UpdateLineBreakMode();
UpdateAlignment();
UpdateText();
UpdateTextDecorations();
UpdateTextColor();
UpdateFont();
}
@ -150,6 +152,8 @@ namespace Xamarin.Forms.Platform.MacOS
UpdateFont();
else if (e.PropertyName == Label.TextProperty.PropertyName)
UpdateText();
else if (e.PropertyName == Label.TextDecorationsProperty.PropertyName)
UpdateTextDecorations();
else if (e.PropertyName == Label.FormattedTextProperty.PropertyName)
UpdateText();
else if (e.PropertyName == Label.LineBreakModeProperty.PropertyName)
@ -160,6 +164,41 @@ namespace Xamarin.Forms.Platform.MacOS
UpdateText();
}
void UpdateTextDecorations()
{
if (!Element.IsSet(Label.TextDecorationsProperty))
return;
var textDecorations = Element.TextDecorations;
#if __MOBILE__
var newAttributedText = new NSMutableAttributedString(Control.AttributedText);
var strikeThroughStyleKey = UIStringAttributeKey.StrikethroughStyle;
var underlineStyleKey = UIStringAttributeKey.UnderlineStyle;
#else
var newAttributedText = new NSMutableAttributedString(Control.AttributedStringValue);
var strikeThroughStyleKey = NSStringAttributeKey.StrikethroughStyle;
var underlineStyleKey = NSStringAttributeKey.UnderlineStyle;
#endif
var range = new NSRange(0, newAttributedText.Length);
if ((textDecorations & TextDecorations.Strikethrough) == 0)
newAttributedText.RemoveAttribute(strikeThroughStyleKey, range);
else
newAttributedText.AddAttribute(strikeThroughStyleKey, NSNumber.FromInt32((int)NSUnderlineStyle.Single), range);
if ((textDecorations & TextDecorations.Underline) == 0)
newAttributedText.RemoveAttribute(underlineStyleKey, range);
else
newAttributedText.AddAttribute(underlineStyleKey, NSNumber.FromInt32((int)NSUnderlineStyle.Single), range);
#if __MOBILE__
Control.AttributedText = newAttributedText;
#else
Control.AttributedStringValue = newAttributedText;
#endif
}
#if __MOBILE__
protected override void SetAccessibilityLabel()
{