Xamarin.forms: [Enhancement] MaxLines on Label

Created on 26 Jan 2018  Â·  9Comments  Â·  Source: xamarin/Xamarin.Forms

Rationale

Labels do not currently have a MaxLines property, so they either display all lines or truncate at the end of one line.

Implementation

Add bindable property to Label:

public static readonly BindableProperty MaxLinesProperty = BindableProperty.Create("MaxLines", typeof(int), typeof(Label), 0);

Renderers will need to be updated accordingly.

Expected Result

Android

  • MaxLines == 0: Default. Label respects the LineBreakMode to either show just one line (possibly truncated) or all lines with all text.
  • MaxLines == 1: Same effect as LineBreakMode.NoWrap or LineBreakMode.*Truncation. Label respects the LineBreakMode as far as placement of ellipsis, if applicable.
  • MaxLines > 1: Has no effect if LineBreakMode is NoWrap. Otherwise, will display up to the specified number of lines and respect the LineBreakMode as far as placement of ellipsis, if applicable.

iOS

See Android

UWP

See Android

Implications for CSS

Label will now support max-lines.

Backward Compatibility

Since we are adding new properties, there should be no compatibility problems as long as:

  1. We ensure that a Label's MaxLines defaults to all (0), as is the expected behavior now, and respects the LineBreakMode.
  2. We ensure that any Effects or Custom Renderers that may have been created to produce this behavior take precedence over any values that we set, to the best of our ability.

Third party renderers will need to be updated to ensure that this functionality is officially supported.

Difficulty : Medium

There is some logic in place on the Label renderers that adjusts the desired size of the Label based on potential wrapping that will need to be thoroughly tested after this change.

F100 community-sprint enhancement âž•

Most helpful comment

We implemented this with a quick and dirty effect. Our use case didn't require responding to changes so we omitted that, but it's worked well and should be straight forward to bake into Label.

Routing effect

public class MaxLinesEffect : RoutingEffect
{
    public int MaxLines { get; set; }

    public MaxLinesEffect() : base($"Highrise.{nameof(MaxLinesEffect)}") { }
}

iOS PlatformEffect

public class MaxLinesPlatformEffect : PlatformEffect
{
    protected override void OnAttached()
    {
        var maxLinesEffect = Element.Effects.FirstOfType<MaxLinesEffect>();
        if (maxLinesEffect == null) {
            return;
        }
        if (Control is UILabel nativeLabel) {
            nativeLabel.Lines = maxLinesEffect.MaxLines;
            nativeLabel.LineBreakMode = UILineBreakMode.TailTruncation;
        }
    }

    protected override void OnDetached() { }
}

Android PlatformEffect

public class MaxLinesPlatformEffect : PlatformEffect
{
    protected override void OnAttached()
    {
        var maxLinesEffect = Element.Effects.FirstOfType<MaxLinesEffect>();
        if (maxLinesEffect == null) {
            return;
        }

        if (Control is TextView nativeTextView) {
            if (maxLinesEffect.MaxLines <= 0) {
                nativeTextView.SetMaxLines(99999);
            } else if (maxLinesEffect.MaxLines == 1) {
                nativeTextView.SetSingleLine(true);
                nativeTextView.Ellipsize = TextUtils.TruncateAt.End;
            } else if (maxLinesEffect.MaxLines > 1) {
                nativeTextView.SetMaxLines(maxLinesEffect.MaxLines);
                nativeTextView.Ellipsize = TextUtils.TruncateAt.End;
            }
        }
    }

    protected override void OnDetached() { }
}

All 9 comments

We implemented this with a quick and dirty effect. Our use case didn't require responding to changes so we omitted that, but it's worked well and should be straight forward to bake into Label.

Routing effect

public class MaxLinesEffect : RoutingEffect
{
    public int MaxLines { get; set; }

    public MaxLinesEffect() : base($"Highrise.{nameof(MaxLinesEffect)}") { }
}

iOS PlatformEffect

public class MaxLinesPlatformEffect : PlatformEffect
{
    protected override void OnAttached()
    {
        var maxLinesEffect = Element.Effects.FirstOfType<MaxLinesEffect>();
        if (maxLinesEffect == null) {
            return;
        }
        if (Control is UILabel nativeLabel) {
            nativeLabel.Lines = maxLinesEffect.MaxLines;
            nativeLabel.LineBreakMode = UILineBreakMode.TailTruncation;
        }
    }

    protected override void OnDetached() { }
}

Android PlatformEffect

public class MaxLinesPlatformEffect : PlatformEffect
{
    protected override void OnAttached()
    {
        var maxLinesEffect = Element.Effects.FirstOfType<MaxLinesEffect>();
        if (maxLinesEffect == null) {
            return;
        }

        if (Control is TextView nativeTextView) {
            if (maxLinesEffect.MaxLines <= 0) {
                nativeTextView.SetMaxLines(99999);
            } else if (maxLinesEffect.MaxLines == 1) {
                nativeTextView.SetSingleLine(true);
                nativeTextView.Ellipsize = TextUtils.TruncateAt.End;
            } else if (maxLinesEffect.MaxLines > 1) {
                nativeTextView.SetMaxLines(maxLinesEffect.MaxLines);
                nativeTextView.Ellipsize = TextUtils.TruncateAt.End;
            }
        }
    }

    protected override void OnDetached() { }
}

@davidortinau I'll take this

@michaeldwan still planning on doing this? We can move this back to available if not. Looks like you are 90% of the way there already anyway.

@michaeldwan are you working on this?

@michaeldwan Any progress? Thanks!

I’m sorry for the slow reply. I’m not going to be able to get this done anytime soon. If this is still open in a few months I’ll try and wrap it up.

Anyone to do it?

Hi, in what version will this be delivered 🙂?

@tmt242001 it's in 3.3.0. We just shipped the first preview of this release today via NuGet. https://developer.xamarin.com/releases/xamarin-forms/xamarin-forms-3.3/3.3.0-pre1/
https://www.nuget.org/packages/Xamarin.Forms/3.3.0.840541-pre1

Was this page helpful?
0 / 5 - 0 ratings