#XfQaD: Limit maximum lines of Label and indicate text truncation

If we want to display some text in our Xamarin.Forms app, chances are high we are going to use the Label control. But what if we want to limit the maximum visible lines of such a Label? This is what this #XfQaD is about.
limited truncated label

The problem

Xamarin.Forms.Labelhas a common set of properties we can use to configure how our text is shown. However, it does miss a property to limit the maximum of text lines and a proper indication of eventually truncated text. Knowing that UWP, Android and iOS have working and easy-to-use implementations on their platform controls used for the Xamarin.Forms.Label, there is only one solution to the problem: exposing a custom control and its platform renderers. That’s what we are going to do in this #XfQaD.

XfMaxLines Label implementation

Let’s have a look at the Xamarin.Forms implementation first. I am just adding a BindablePropertyto a derived class implementation to define the maximum of lines I want to see:

public class XfMaxLinesLabel : Label
{
    public XfMaxLinesLabel(){ }

    public static BindableProperty MaxLinesProperty = BindableProperty.Create("MaxLines", typeof(int), typeof(XfMaxLinesLabel), int.MaxValue, BindingMode.Default);

    public int MaxLines
    {
        get => (int)GetValue(MaxLinesProperty);
        set => SetValue(MaxLinesProperty, value);
    }
}

UWP

The UWP renderer uses the TextBlock properties MaxLinesto limit the amount of shown lines, while the TextTrimmingproperty is set to ellipsize the last word before reaching the limit. The implementation is pretty straight forward:

[assembly: ExportRenderer(typeof(XfMaxLinesLabel), typeof(XfMaxLinesLabelRenderer))]
namespace MaxLinesLabel.UWP
{
    public class XfMaxLinesLabelRenderer : LabelRenderer
    {
        protected override void OnElementChanged(ElementChangedEventArgs<Label> e)
        {
            base.OnElementChanged(e);

            if (((XfMaxLinesLabel)e.NewElement).MaxLines == -1 || ((XfMaxLinesLabel)e.NewElement).MaxLines == int.MaxValue)
                return;

            this.Control.MaxLines = ((XfMaxLinesLabel)e.NewElement).MaxLines;
            this.Control.TextTrimming = Windows.UI.Xaml.TextTrimming.WordEllipsis;
        }

        protected override void OnElementPropertyChanged(object sender, PropertyChangedEventArgs e)
        {
            base.OnElementPropertyChanged(sender, e);

            if (e.PropertyName == XfMaxLinesLabel.MaxLinesProperty.PropertyName)
            {
                if (((XfMaxLinesLabel)this.Element).MaxLines == -1 || ((XfMaxLinesLabel)this.Element).MaxLines == int.MaxValue)
                    return;

                this.Control.MaxLines = ((XfMaxLinesLabel)this.Element).MaxLines;
                this.Control.TextTrimming = Windows.UI.Xaml.TextTrimming.WordEllipsis;
            }
        }
    }
}

Android

The Android implementation uses the MaxLinesproperty of Android’s TextView control to limit the maximum visible lines. The Ellipsizeproperty is used to show the three dots for truncation at the end of the last visible line. Once again, pretty straight forward.

[assembly: ExportRenderer(typeof(XfMaxLinesLabel), typeof(XfMaxLinesLabelRenderer))]
namespace MaxLinesLabel.Droid
{
    class XfMaxLinesLabelRenderer : LabelRenderer
    {
        public XfMaxLinesLabelRenderer(Context context) : base(context)
        {
        }


        protected override void OnElementChanged(ElementChangedEventArgs<Label> e)
        {
            base.OnElementChanged(e);

            if (((XfMaxLinesLabel)e.NewElement).MaxLines == -1 || ((XfMaxLinesLabel)e.NewElement).MaxLines == int.MaxValue)
                return;
            this.Control.SetMaxLines(((XfMaxLinesLabel)e.NewElement).MaxLines);
            this.Control.Ellipsize = TextUtils.TruncateAt.End;
        }


        protected override void OnElementPropertyChanged(object sender, PropertyChangedEventArgs e)
        {
            base.OnElementPropertyChanged(sender, e);

            if (e.PropertyName == XfMaxLinesLabel.MaxLinesProperty.PropertyName)
            {
                if (((XfMaxLinesLabel)this.Element).MaxLines == -1 || ((XfMaxLinesLabel)this.Element).MaxLines == int.MaxValue)
                    return;
                this.Control.SetMaxLines(((XfMaxLinesLabel)this.Element).MaxLines);
                this.Control.Ellipsize = TextUtils.TruncateAt.End;
            }
        }
    }
}

iOS

Like Android and Windows, also the UILabel control on iOS has a MaxLinesproperty. You’re right, we’ll use this one to limit the count of visible lines. Using the LineBreakModeproperty, we can automate the text truncation indicator equally easy as on Android and UWP:

[assembly: ExportRenderer(typeof(XfMaxLinesLabel), typeof(XfMaxLinesLabelRenderer))]
namespace MaxLinesLabel.iOS
{
    public class XfMaxLinesLabelRenderer : LabelRenderer
    {
        protected override void OnElementChanged(ElementChangedEventArgs<Label> e)
        {
            base.OnElementChanged(e);

            if (((XfMaxLinesLabel)e.NewElement).MaxLines == -1 || ((XfMaxLinesLabel)e.NewElement).MaxLines == int.MaxValue)
                return;

            this.Control.Lines = ((XfMaxLinesLabel)e.NewElement).MaxLines;
            this.Control.LineBreakMode = UILineBreakMode.TailTruncation;
        }

        protected override void OnElementPropertyChanged(object sender, PropertyChangedEventArgs e)
        {
            base.OnElementPropertyChanged(sender, e);

            if (e.PropertyName == XfMaxLinesLabel.MaxLinesProperty.PropertyName)
            {
                if (((XfMaxLinesLabel)this.Element).MaxLines == -1 || ((XfMaxLinesLabel)this.Element).MaxLines == int.MaxValue)
                    return;

                this.Control.Lines = ((XfMaxLinesLabel)this.Element).MaxLines;
                this.Control.LineBreakMode = UILineBreakMode.TailTruncation;
            }
        }
    }
}

Conclusion

As you can see, it is pretty easy to create a line limited, truncation indicating custom Label for your Xamarin.Forms app. The implementation is done in a few minutes, but it makes writing your cross platform app a bit easier. I don’t know why this is not (yet) implemented in current Xamarin.Forms iterations, but I do hope they’ll do so to further reduce the number of needed custom renderers.

In the meantime, feel free to check the sample code on GitHub and use it in your apps. As always, I hope this post is helpful for some of you.

Happy coding, everyone!

Comments 1

Join the discussion right now!

This site uses Akismet to reduce spam. Learn how your comment data is processed.

Prev
WordPressReader (Standard) library is now available on Nuget
WP Lib Title

WordPressReader (Standard) library is now available on Nuget

Next
Xamarin Android: asymmetric encryption without any user input or hardcoded values
lock_encyprtion_title_android

Xamarin Android: asymmetric encryption without any user input or hardcoded values

You May Also Like

This website uses cookies. By continuing to use this site, you accept the use of cookies.  Learn more