Xamarin forms – multi line label custom renderer gotcha

** UPDATE **

We expanded this and added an Effect for eveyone to use in the Xamarin Forms Community Toolkit!
It’s available here : https://github.com/FormsCommunityToolkit/FormsCommunityToolkit
The effect itself resides here : https://github.com/FormsCommunityToolkit/FormsCommunityToolkit/tree/dev/src/Effects/Effects/Label

On a project I’m working on, we needed a label that would show an ellipsis at the end. ( the 3 … indicating there is more text but not enough space on the screen to fit it all )

Having this on a label control in Xamarin forms is easy, you just add the property

this will force the ellipsis to appear if needed.

But on a specific page we wanted to show more text to the end user and even than add an ellipsis if needed. So in other words we would love to be able to tell the label control how many lines it should at least try to display.
To get this working in Xamarin forms you’ll need to add a custom renderer. Because the Xamarin forms label control doesn’t have any property available for us to manipulate to accomplish this.

This is not difficult at all to do, but there is a small gotcha with Android when you want to pull this off!

But let’s start with what you need to do to get this working.
In the Xamarin forms PCL ( so the general one, not the iOS or Android project ), we first add a class called MultiLineLabel.cs – this will be our own custom control.
It inherits from Label and we only need to add 1 dependency property called Lines, defined as an int. It looks like this:

After defining this custom control, we can use it on our XAML page, like so:

We will be using this Lines property in our custom renderers.
First up the iOS custom renderer for our MultiLineLabel. Create a class in the Xamarin forms iOS project called CustomMultiLineLabelRenderer.cs with following code:

You’ll notice that we are checking if the user specified a value for the Lines dependency property and if this is true, we pass this to the actual iOS UIKit.UILabel control by setting it’s Lines property. With this in place we get following result.

Screen Shot 2016-06-27 at 08.31.08

So iOS is done and looking great. Now add the Android renderer. Create a CustomMultiLineLabelRenderer.cs class in the Xamarin forms Android project with following code:

This doesn’t look all that different from the iOS counterpart… instead of setting a property we now use a method SetLines on the Android.Widget.TextView indicating how many lines we want it to display.
But wait, if we try this and look at the result, we’ll notice that it doesn’t work!!

Screen Shot 2016-06-27 at 08.31.05

It took me a while to figure this out ( I’m no Android expert πŸ˜‰ ). But after taking a look in the Xamarin forms source code ( glad it’s open source πŸ˜‰ ) I noticed they will always force a SetSingleLine(true) when setting the TailTruncation LineBreakMode…
Code can be seen here https://github.com/xamarin/Xamarin.Forms/blob/2d9288eee6e6f197364a64308183725e7bd561f9/Xamarin.Forms.Platform.Android/Renderers/LabelRenderer.cs#L179

So the fix is easy… you need to reset this Single Line forcing, the final code looks like this ( in your custom renderer ) :

With that in place we’ll get following result

Screen Shot 2016-06-27 at 08.31.31

Yeah success!
To start I’ve done a pull request on Xamarin forms to counter this SingleLine forcing, but not sure this will be added though… https://github.com/xamarin/Xamarin.Forms/pull/234
So better be safe and add the extra line in your own custom renderer for now.

As always example project up on github here…

16 thoughts on “Xamarin forms – multi line label custom renderer gotcha”

  1. This helped me alot! Thank you very much!!
    But what about a solution for windows phones?

  2. Good question, I have to say I haven’t looked at that myself yet… Is it a problem on UWP and Windows Phone 8.1? Unable to add these projects on my MacBook Xamarin Studio

  3. At the moment I have only testet on Windows Phone 8.1
    I copied the renderer from iOS.
    It complains on the Line in: Control.Lines = multiLineLabel.Lines;
    error msg = ‘TextBlock’ does not contain a definition for ‘Lines’ and no extension method ‘Lines’ accepting a first argument of type ‘TextBlock’ could be found (are you missing a using directive or an assembly reference?)
    I’m very new to programming. :/ =)

  4. I changed the code to: Control.MaxLines = multiLineLabel.Lines;
    No more errors but it dosen’t work, the labels only show one line.

  5. Hi
    I was just wondering, if it’d be also possible to create multiline labels in the c# source.

    Lets say the following code:

    MultiLineLabel ProductName = new MultiLineLabel()
    {
    FontSize = 12
    // BackgroundColor = Color.Red

    };
    ProductName.SetBinding(Label.TextProperty, “sName”);
    ProductName.LineBreakMode = LineBreakMode.TailTruncation;
    ProductName.Lines = 2;

    The Label shows up but doesnt have 2 lines.. I assume, thats because the custom render method is not been called.

    Do you know how that problem may be fixed?

    Thanks for the great post!

  6. Okay.. If I would have read some more lines, I would have seen the fix for android πŸ˜‰
    Works perfect – Thanks again!

  7. That is weird, so long as the setup for the custom renderer is done right is should be called even if you add it through code

  8. Do you have any idea, how to accomplish a behavior where it works exactly as described in this article but in addition, if user taps on the label, it would show the full contents (removing the ellipsis and MaxLines property)?

  9. Hey Sammy, not done that yet myself. But I guess you’ll need to hook up to tap gestures inside the custom renderers.
    Example for iOS:
    UITapGestureRecognizer labelTap = new UITapGestureRecognizer(() => {
    // Do something in here
    });
    myLabel.UserInteractionEnabled = true;
    myLabel.AddGestureRecognizer(labelTap);

    Inside the code you can change the properties again.
    BUT not sure if this will invalidate the layout, so that the UI will render the label again.
    Anyhow worth a shot I guess.

  10. I wrote a renderer for UWP, if anyone needs one:


    [assembly: ExportRenderer(typeof(MultiLineLabel), typeof(MultiLineLabelRenderer))]
    namespace DearDiary.Frontend.Forms.UWP.Renderers
    {
    public class MultiLineLabelRenderer : Xamarin.Forms.Platform.UWP.LabelRenderer
    {
    protected override void OnElementChanged(ElementChangedEventArgs e)
    {
    base.OnElementChanged(e);

    MultiLineLabel multiLineLabel = (MultiLineLabel)Element;

    if (multiLineLabel != null && multiLineLabel.Lines != -1)
    {
    Control.MaxLines = multiLineLabel.Lines;
    }
    }
    }
    }

  11. I did same in my project but didn’t think about to write a blog on that, its now inspiration for me.

    Thanks

Leave a Reply

Your email address will not be published. Required fields are marked *