Search code examples
androidxamarin.formslabelmultilinecustom-renderer

Xamarin.Forms: the MultiLineLabel doesn't longer work on Android


On my Xamarin.Forms project, I use a MultiLineLabel to display a title on 1 or 2 lines, depending the text length. I'm based on this blog to achieve this.

So I have a MultiLineLabel control:

public class MultiLineLabel : Label
{
    private static int _defaultLineSetting = -1;

    public static readonly BindableProperty LinesProperty = BindableProperty.Create(nameof(Lines), typeof(int), typeof(MultiLineLabel), _defaultLineSetting);
    public int Lines
    {
        get { return (int)GetValue(LinesProperty); }
        set { SetValue(LinesProperty, value); }
    }
}

I use 2 renderers:

  • on iOS, I've kept the given renderer:

    public class CustomMultiLineLabelRenderer : LabelRenderer
    {
        protected override void OnElementChanged(ElementChangedEventArgs<Label> e)
        {
            base.OnElementChanged(e);
    
            MultiLineLabel multiLineLabel = (MultiLineLabel)Element;
    
            if (multiLineLabel != null && multiLineLabel.Lines != -1)
                Control.Lines = multiLineLabel.Lines;
    
        }
    }
    
  • on Android I've customized the renderer:

    public class CustomMultiLineLabelRenderer : LabelRenderer
    {
        protected override void OnElementChanged(ElementChangedEventArgs<Label> e)
        {
            base.OnElementChanged(e);
    
            MultiLineLabel multiLineLabel = (MultiLineLabel)Element;
    
            if (multiLineLabel != null && multiLineLabel.Lines != -1)
            {
                Control.Ellipsize = TextUtils.TruncateAt.End;
                Control.SetMaxLines(multiLineLabel.Lines);
            }
        }
    }
    

And I use this MultiLineLabel like this in XAML:

<StackLayout 
    Grid.Row="0"
    Spacing="0">

    <local:MultiLineLabel
        Margin="8,6,8,0"
        TextColor="{ DynamicResource InverseTextColor }"
        Text="{ Binding encart_titre }"
        FontSize="{ artina:OnOrientationDouble 
            Default=16,
            PortraitTablet=20,
            LandscapeTablet=20 }"
        LineBreakMode="TailTruncation"
        Lines="2"
        Grid.Column="0"
        BackgroundColor="Yellow"
    />
</StackLayout>

Until I used Xamarin.Forms v.2.3.4.247, this worked well on Android:

screenshot before update

But after having updated to the latest version (Xamarin.Forms v.2.4.0.269-pre2), it doesn't longer work as expected:

screenshot after update

I also tried to use the renderer given on the blog:

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

    MultiLineLabel multiLineLabel = (MultiLineLabel)Element;

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

But I didn't get the expected rendering: screenshot after updater - alternative

Would you have any explanation? Or another suggestion? On iOS this works well.


Solution

  • But after having updated to the latest version (Xamarin.Forms v.2.4.0.269-pre2), it doesn't longer work as expected:

    Cause:

    I've checked the source codes of Xamarin.Forms v.2.4.0.269-pre2. In LabelRenderer's OnElementChange event, FormsTextView's SetLineBreakMode will be called which contains following codes:

    public static void SetLineBreakMode(this TextView textView, LineBreakMode lineBreakMode)
    {
        switch (lineBreakMode)
        {
            case LineBreakMode.NoWrap:
                textView.SetMaxLines(1);
                textView.SetSingleLine(true);
                textView.Ellipsize = null;
                break;
            case LineBreakMode.WordWrap:
                textView.Ellipsize = null;
                textView.SetMaxLines(100);
                textView.SetSingleLine(false);
                break;
            case LineBreakMode.CharacterWrap:
                textView.Ellipsize = null;
                textView.SetMaxLines(100);
                textView.SetSingleLine(false);
                break;
            case LineBreakMode.HeadTruncation:
                textView.SetMaxLines(1);
                textView.SetSingleLine(true);
                textView.Ellipsize = TextUtils.TruncateAt.Start;
                break;
            case LineBreakMode.TailTruncation:
                textView.SetMaxLines(1);
                textView.SetSingleLine(true);
                textView.Ellipsize = TextUtils.TruncateAt.End;
                break;
            case LineBreakMode.MiddleTruncation:
                textView.SetMaxLines(1);
                textView.SetSingleLine(true);
                textView.Ellipsize = TextUtils.TruncateAt.Middle;
                break;
        }
    }
    

    As you can see, if you use LineBreakMode.TailTruncation, textView.SetMaxLines(1); and textView.SetSingleLine(true); will be called, which disable the multi line function.(In 2.3.4 textView.SetSingleLine(true); doesn't exist).

    Solution:

    To fix the problem, you simply need to add two lines of codes in your renderer:

    protected override void OnElementChanged(ElementChangedEventArgs<Xamarin.Forms.Label> e)
    {
        base.OnElementChanged(e);
        MultiLineLabel multiLineLabel = (MultiLineLabel)Element;
    
        if (multiLineLabel != null && multiLineLabel.Lines != -1)
        {
            Control.SetSingleLine(false);
            Control.SetMaxLines(multiLineLabel.Lines);
            Control.SetLines(multiLineLabel.Lines);
    
        }
    }