Skip to content

Commit

Permalink
Implemented LineHeight on Label (#538)
Browse files Browse the repository at this point in the history
* Implemented LineHeight on Label (#368)

* Fix-up after rebase

Co-authored-by: E.Z. Hart <hartez@gmail.com>
  • Loading branch information
AmrAlSayed0 and hartez committed Mar 17, 2021
1 parent 108e7a4 commit 699becd
Show file tree
Hide file tree
Showing 14 changed files with 163 additions and 28 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -248,6 +248,7 @@ void UpdateCharacterSpacing()
}
}

[PortHandler]
void UpdateLineHeight()
{
_lastSizeRequest = null;
Expand Down
1 change: 1 addition & 0 deletions src/Compatibility/Core/src/iOS/Renderers/LabelRenderer.cs
Original file line number Diff line number Diff line change
Expand Up @@ -431,6 +431,7 @@ void UpdateCharacterSpacing()
_perfectSizeValid = false;
}

[PortHandler("Partially. Mapped LineHeight")]
void UpdateText()
{
if (IsElementOrControlEmpty)
Expand Down
1 change: 1 addition & 0 deletions src/Controls/samples/Controls.Sample/Pages/MainPage.cs
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@ void SetupMauiLayout()
verticalStack.Add(new Label { Text = loremIpsum, MaxLines = 2 });
verticalStack.Add(new Label { Text = loremIpsum, LineBreakMode = LineBreakMode.TailTruncation });
verticalStack.Add(new Label { Text = loremIpsum, MaxLines = 2, LineBreakMode = LineBreakMode.TailTruncation });
verticalStack.Add(new Label { Text = "This should have five times the line height!", LineHeight = 5});


var paddingButton = new Button
Expand Down
7 changes: 6 additions & 1 deletion src/Core/src/Core/ILabel.cs
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,13 @@ public interface ILabel : IView, IText, ITextAlignment, IPadding

/// <summary>
/// Gets the text decoration applied to the Label.
/// Underline and strikethrough text decorations can be applied.
/// Underline and strike-through text decorations can be applied.
/// </summary>
TextDecorations TextDecorations { get; }
/// <summary>
/// Gets the line height applied to the Label.
/// Underline and strike-through text decorations can be applied.
/// </summary>
double LineHeight { get; }
}
}
8 changes: 8 additions & 0 deletions src/Core/src/Handlers/Label/LabelHandler.Android.cs
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@ namespace Microsoft.Maui.Handlers
public partial class LabelHandler : AbstractViewHandler<ILabel, TextView>
{
static Color DefaultTextColor { get; set; }
static float LineSpacingAddDefault { get; set; }
static float LineSpacingMultDefault { get; set; }

protected override TextView CreateNativeView() => new TextView(Context);

Expand All @@ -20,6 +22,8 @@ protected override void SetupDefaults(TextView nativeView)
{
DefaultTextColor = Color.FromUint((uint)nativeView.TextColors.DefaultColor);
}
LineSpacingAddDefault = nativeView.LineSpacingExtra;
LineSpacingMultDefault = nativeView.LineSpacingMultiplier;
}

public static void MapText(LabelHandler handler, ILabel label)
Expand Down Expand Up @@ -70,5 +74,9 @@ public static void MapFont(LabelHandler handler, ILabel label)

handler.TypedNativeView?.UpdateFont(label, fontManager);
}
public static void MapLineHeight(LabelHandler handler, ILabel label)
{
handler.TypedNativeView?.UpdateLineHeight(label, LineSpacingAddDefault, LineSpacingMultDefault);
}
}
}
1 change: 1 addition & 0 deletions src/Core/src/Handlers/Label/LabelHandler.Standard.cs
Original file line number Diff line number Diff line change
Expand Up @@ -15,5 +15,6 @@ public static void MapLineBreakMode(LabelHandler handler, ILabel label) { }
public static void MapTextDecorations(LabelHandler handler, ILabel label) { }
public static void MapMaxLines(IViewHandler handler, ILabel label) { }
public static void MapPadding(LabelHandler handler, ILabel label) { }
public static void MapLineHeight(LabelHandler handler, ILabel label) { }
}
}
3 changes: 2 additions & 1 deletion src/Core/src/Handlers/Label/LabelHandler.cs
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,8 @@ public partial class LabelHandler
[nameof(ILabel.HorizontalTextAlignment)] = MapHorizontalTextAlignment,
[nameof(ILabel.LineBreakMode)] = MapLineBreakMode,
[nameof(ILabel.Padding)] = MapPadding,
[nameof(ILabel.TextDecorations)] = MapTextDecorations
[nameof(ILabel.TextDecorations)] = MapTextDecorations,
[nameof(ILabel.LineHeight)] = MapLineHeight
};

public LabelHandler() : base(LabelMapper)
Expand Down
5 changes: 5 additions & 0 deletions src/Core/src/Handlers/Label/LabelHandler.iOS.cs
Original file line number Diff line number Diff line change
Expand Up @@ -56,5 +56,10 @@ public static void MapFont(LabelHandler handler, ILabel label)

handler.TypedNativeView?.UpdateFont(label, fontManager);
}

public static void MapLineHeight(LabelHandler handler, ILabel label)
{
handler.TypedNativeView?.UpdateLineHeight(label);
}
}
}
8 changes: 8 additions & 0 deletions src/Core/src/Platform/Android/TextViewExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -143,5 +143,13 @@ internal static void SetLineBreakMode(this TextView textView, ILabel label)
textView.SetSingleLine(singleLine);
textView.SetMaxLines(maxLines);
}

internal static void UpdateLineHeight(this TextView textView, ILabel label, float lineSpacingAddDefault, float lineSpacingMultDefault)
{
if (label.LineHeight == - 1)
textView.SetLineSpacing(lineSpacingAddDefault, lineSpacingMultDefault);
else if (label.LineHeight >= 0)
textView.SetLineSpacing(0, (float)label.LineHeight);
}
}
}
60 changes: 34 additions & 26 deletions src/Core/src/Platform/iOS/LabelExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -79,32 +79,6 @@ public static void UpdatePadding(this MauiLabel nativeLabel, ILabel label)
(float)label.Padding.Right);
}

public static void UpdateTextDecorations(this UILabel nativeLabel, ILabel label)
{
if (nativeLabel.AttributedText != null && !(nativeLabel.AttributedText?.Length > 0))
return;

var textDecorations = label?.TextDecorations;

var newAttributedText = nativeLabel.AttributedText != null ? new NSMutableAttributedString(nativeLabel.AttributedText) : new NSMutableAttributedString(label?.Text ?? string.Empty);
var strikeThroughStyleKey = UIStringAttributeKey.StrikethroughStyle;
var underlineStyleKey = UIStringAttributeKey.UnderlineStyle;

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);

nativeLabel.AttributedText = newAttributedText;
}

internal static void SetLineBreakMode(this UILabel nativeLabel, ILabel label)
{
int maxLines = label.MaxLines;
Expand Down Expand Up @@ -139,5 +113,39 @@ internal static void SetLineBreakMode(this UILabel nativeLabel, ILabel label)

nativeLabel.Lines = maxLines;
}

public static void UpdateTextDecorations(this UILabel nativeLabel, ILabel label)
{
if (nativeLabel.AttributedText != null && !(nativeLabel.AttributedText?.Length > 0))
return;

var textDecorations = label?.TextDecorations;

var newAttributedText = nativeLabel.AttributedText != null ? new NSMutableAttributedString(nativeLabel.AttributedText) : new NSMutableAttributedString(label?.Text ?? string.Empty);
var strikeThroughStyleKey = UIStringAttributeKey.StrikethroughStyle;
var underlineStyleKey = UIStringAttributeKey.UnderlineStyle;

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);

nativeLabel.AttributedText = newAttributedText;
}

internal static void UpdateLineHeight(this UILabel nativeLabel, ILabel label)
{
var modAttrText = nativeLabel.AttributedText?.WithLineHeight(label.LineHeight);

if (modAttrText != null)
nativeLabel.AttributedText = modAttrText;
}
}
}
25 changes: 25 additions & 0 deletions src/Core/src/Platform/iOS/NSAttributedStringExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -25,5 +25,30 @@ public static class NSAttributedStringExtensions
);
return mutableAttributedString;
}

public static NSMutableAttributedString? WithLineHeight(this NSAttributedString attributedString, double lineHeight)
{
if (attributedString == null || attributedString.Length == 0)
return null;

var attribute = (NSParagraphStyle) attributedString.GetAttribute(UIStringAttributeKey.ParagraphStyle, 0, out _);

// if we need to un-set the line height but there is no attribute to modify then we do nothing
if (lineHeight == -1 && attribute == null)
return null;

var mutableParagraphStyle = new NSMutableParagraphStyle();
mutableParagraphStyle.LineHeightMultiple = new System.nfloat(lineHeight >= 0 ? lineHeight : -1);

var mutableAttributedString = new NSMutableAttributedString(attributedString);
mutableAttributedString.AddAttribute
(
UIStringAttributeKey.ParagraphStyle,
mutableParagraphStyle ,
new NSRange(0, mutableAttributedString.Length)
);

return mutableAttributedString;
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -137,6 +137,31 @@ public async Task TextDecorationsInitializesCorrectly()
values.NativeViewValue.AssertHasFlag(expectedValue);
}

[Fact(DisplayName = "LineHeight Initializes Correctly")]
public async Task LineHeightInitializesCorrectly()
{
var xplatLineHeight = 1.5d;

var labelHandler = new LabelStub()
{
LineHeight = xplatLineHeight
};

var values = await GetValueAsync(labelHandler, (handler) =>
{
return new
{
ViewValue = labelHandler.LineHeight,
NativeViewValue = GetNativeLineHeight(handler)
};
});

float expectedValue = 1.5f;

Assert.Equal(xplatLineHeight, values.ViewValue);
Assert.Equal(expectedValue, values.NativeViewValue);
}

TextView GetNativeLabel(LabelHandler labelHandler) =>
(TextView)labelHandler.View;

Expand Down Expand Up @@ -188,5 +213,8 @@ TextUtils.TruncateAt GetNativeLineBreakMode(LabelHandler labelHandler) =>

PaintFlags GetNativeTextDecorations(LabelHandler labelHandler) =>
GetNativeLabel(labelHandler).PaintFlags;

float GetNativeLineHeight(LabelHandler labelHandler) =>
GetNativeLabel(labelHandler).LineSpacingMultiplier;
}
}
41 changes: 41 additions & 0 deletions src/Core/tests/DeviceTests/Handlers/Label/LabelHandlerTests.iOS.cs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
using System;
using System.Threading.Tasks;
using Foundation;
using Microsoft.Extensions.DependencyInjection;
Expand Down Expand Up @@ -118,6 +119,31 @@ public async Task TextDecorationsInitializesCorrectly()
Assert.NotNull(values.NativeViewValue);
}

[Fact(DisplayName = "LineHeight Initializes Correctly")]
public async Task LineHeightInitializesCorrectly()
{
var xplatLineHeight = 1.5d;

var labelHandler = new LabelStub()
{
Text = "test",
LineHeight = xplatLineHeight
};

var values = await GetValueAsync(labelHandler, (handler) =>
{
return new
{
ViewValue = labelHandler.LineHeight,
NativeViewValue = GetNativeLineHeight(handler)
};
});

nfloat expectedValue = new nfloat(1.5f);
Assert.Equal(xplatLineHeight, values.ViewValue);
Assert.Equal(expectedValue, values.NativeViewValue);
}

UILabel GetNativeLabel(LabelHandler labelHandler) =>
(UILabel)labelHandler.View;

Expand Down Expand Up @@ -162,5 +188,20 @@ UILineBreakMode GetNativeLineBreakMode(LabelHandler labelHandler) =>

NSAttributedString GetNativeTextDecorations(LabelHandler labelHandler) =>
GetNativeLabel(labelHandler).AttributedText;

nfloat GetNativeLineHeight(LabelHandler labelHandler)
{
var attrText = GetNativeLabel(labelHandler).AttributedText;

if(attrText == null)
return new nfloat(-1.0f);

var paragraphStyle = (NSParagraphStyle)attrText.GetAttribute(UIStringAttributeKey.ParagraphStyle, 0, out _);

if(paragraphStyle == null)
return new nfloat(-1.0f);

return paragraphStyle.LineHeightMultiple;
}
}
}
2 changes: 2 additions & 0 deletions src/Core/tests/DeviceTests/Stubs/LabelStub.cs
Original file line number Diff line number Diff line change
Expand Up @@ -19,5 +19,7 @@ public partial class LabelStub : StubBase, ILabel
public TextDecorations TextDecorations { get; set; }

public int MaxLines { get; set; } = -1;

public double LineHeight { get; set; } = -1;
}
}

0 comments on commit 699becd

Please sign in to comment.