Multi-line Label with tail truncation

JonCortezJonCortez USUniversity ✭✭

Is a Label in XF configurable to support multi-line (wraps) and tail truncation at the same time? In iOS, I can do this by specifying the number of lines on a UILabel and specifying tail truncation. If not, I can also go the custom renderer route.

Posts

  • CraigDunnCraigDunn USXamarin Team Xamurai

    Doesn't look like it, as soon as I enable LineBreakMode = LineBreakMode.TailTruncation then it stops wrapping across lines to fill the available height, and instead truncates at the end of line one.

  • JonCortezJonCortez USUniversity ✭✭

    Yup, that seems to be the behavior. I will try the custom renderer route since I also need to be able to change the line spacing of the wrapped text in a Label.

  • IPutuYogaPermanaIPutuYogaPermana IDMember ✭✭

    maybe anyone have a custom renderer sample or solution for a Multi-line Label with tail truncation ? Thank you :smiley:

  • Anyone got a solution for this?

  • David_PilkingtonDavid_Pilkington USUniversity

    Still no solution to this I take it?

  • TamasMatraiTamasMatrai HUUniversity ✭✭

    No solution?

  • TobeTobe DEMember ✭✭

    Hi,

    Both Android and iOS have a "Lines" property that you can set. The LineBreakMode from Xamarin works no matter how many lines you set.
    This is a very basic implementation, I didn't bother to enable binding for this property, so changing "Lines" while the object is created won't have any effect i guess.

    In custom renderers "Element" is your object that you use in the shared Code (in this case MultiLineLabel) and "Control" is the object that is used on the specific platform(in this case Android.Widget.TextView respectively UIKit.UILabel).
    You can just look through the IntelliSense for Control and usually you find what you need ;-)

    MultiLineLabel.cs (put in shared project):

    using Xamarin.Forms;
    namespace MyNamespace
    {
        public class MultiLineLabel : Label
        {
            // Default number of lines is 1 so MultiLineLabel behaves like a standard Label if Lines is not set
            public int Lines = 1;   
        }
    }
    

    MultiLineLabelRendererIOS.cs (put in iOS project):

    using MyNamescpace;
    using MyNamescpace.iOS;
    using Xamarin.Forms;
    using Xamarin.Forms.Platform.iOS;
    
    [assembly: ExportRenderer(typeof(MultiLineLabel), typeof(MultiLineLabelRendererIOS))]
    namespace MyNamespace.iOS
    {
        public class MultiLineLabelRendererIOS : LabelRenderer
        {
            protected override void OnElementChanged(ElementChangedEventArgs<Label> e)
            {
                base.OnElementChanged(e);
    
                var baseLabel = (MultiLineLabel)this.Element;
    
                Control.Lines = baseLabel.Lines;
            }
    
        }
    }
    

    MultiLineRendererDroid.cs (put in Android project):

    using Xamarin.Forms;
    using Xamarin.Forms.Platform.Android;
    using MyNamescpace;
    using MyNamescpace.Droid;
    
    [assembly: ExportRenderer(typeof(MultiLineLabel), typeof(MultiLineLabelRendererDroid))]
    namespace MyNamescpace.Droid
    {
        public class MultiLineLabelRendererDroid : LabelRenderer
        {
            protected override void OnElementChanged(ElementChangedEventArgs<Label> e)
            {
                base.OnElementChanged(e);
    
                var baseLabel = (MultiLineLabel)this.Element;
    
                Control.SetLines(baseLabel.Lines);
            }
        }
    }
    

    Usage in shared code:

    var lblTest = new MultiLineLabel
        {
            LineBreakMode = LineBreakMode.TailTruncation,
            Lines = 2
        };
    

    Hope this helps,

    Greetings, Tobi

  • Gigex42Gigex42 USMember ✭✭✭✭

    Great work thanks Tobi. But is there some way also for UWP?

    Tried using Control.MaxLines = baseLabel.Lines; but when setting LineBreakMode to TailTruncation it will reset it to just 1 line. When using WortWrap and multiple Lines it works but im missing the three dots here :D

  • TobeTobe DEMember ✭✭
    edited April 2017

    Sorry, we don't use UWP.
    Maybe, in your Custom Renderer, you can use TextTrimming.CharacterEllipsis:
    https://msdn.microsoft.com/de-de/library/system.windows.texttrimming(v=vs.110).aspx

    Have a look at this:
    https://bugzilla.xamarin.com/show_bug.cgi?id=42519

    I have a workaround with a custom renderer that sort of works:

    I need to set the platform specific truncation for the control, Control.TextTrimming = Windows.UI.Xaml.TextTrimming.CharacterEllipsis;

  • Pierre-ChristopheDusPierre-ChristopheDus FRUniversity ✭✭✭

    Hi guys,
    Does the Android renderer always work with the latest version of Xamarin.Forms?
    I just come to update Xamarin.Forms on my project, and the MultilineLabel doesn't longer work on Android. On iOS there is no problem...

  • kay91kay91 MWMember

    @Gigex42 said:
    Great work thanks Tobi. But is there some way also for UWP?

    Tried using Control.MaxLines = baseLabel.Lines; but when setting LineBreakMode to TailTruncation it will reset it to just 1 line. When using WortWrap and multiple Lines it works but im missing the three dots here :D

    In addition to setting the max lines, I also used Control.Ellipsize = TextUtils.TruncateAt.End; in my android custom renderer to show the three dots.

  • vesterdekvesterdek USUniversity

    Looks like at least .characterWrap truncation mode allows both multiline-ness and a proper wrapping, on both Windows 8.1 and UWP. Some other modes may work as well, but I haven't checked. Tested on Xamarin Forms 2.3.4.270. So if you don't absolutely need .tailTruncate that might help

  • amirvenusamirvenus USMember ✭✭✭

    @Tobe said:
    Hi,

    Both Android and iOS have a "Lines" property that you can set. The LineBreakMode from Xamarin works no matter how many lines you set.
    This is a very basic implementation, I didn't bother to enable binding for this property, so changing "Lines" while the object is created won't have any effect i guess.

    In custom renderers "Element" is your object that you use in the shared Code (in this case MultiLineLabel) and "Control" is the object that is used on the specific platform(in this case Android.Widget.TextView respectively UIKit.UILabel).
    You can just look through the IntelliSense for Control and usually you find what you need ;-)

    MultiLineLabel.cs (put in shared project):

    using Xamarin.Forms;
    namespace MyNamespace
    {
      public class MultiLineLabel : Label
      {
          // Default number of lines is 1 so MultiLineLabel behaves like a standard Label if Lines is not set
          public int Lines = 1;   
      }
    }
    

    MultiLineLabelRendererIOS.cs (put in iOS project):

    using MyNamescpace;
    using MyNamescpace.iOS;
    using Xamarin.Forms;
    using Xamarin.Forms.Platform.iOS;
    
    [assembly: ExportRenderer(typeof(MultiLineLabel), typeof(MultiLineLabelRendererIOS))]
    namespace MyNamespace.iOS
    {
      public class MultiLineLabelRendererIOS : LabelRenderer
      {
          protected override void OnElementChanged(ElementChangedEventArgs<Label> e)
          {
              base.OnElementChanged(e);
    
              var baseLabel = (MultiLineLabel)this.Element;
    
              Control.Lines = baseLabel.Lines;
          }
    
      }
    }
    

    MultiLineRendererDroid.cs (put in Android project):

    using Xamarin.Forms;
    using Xamarin.Forms.Platform.Android;
    using MyNamescpace;
    using MyNamescpace.Droid;
    
    [assembly: ExportRenderer(typeof(MultiLineLabel), typeof(MultiLineLabelRendererDroid))]
    namespace MyNamescpace.Droid
    {
      public class MultiLineLabelRendererDroid : LabelRenderer
      {
          protected override void OnElementChanged(ElementChangedEventArgs<Label> e)
          {
              base.OnElementChanged(e);
    
              var baseLabel = (MultiLineLabel)this.Element;
    
              Control.SetLines(baseLabel.Lines);
          }
      }
    }
    

    Usage in shared code:

    var lblTest = new MultiLineLabel
      {
          LineBreakMode = LineBreakMode.TailTruncation,
          Lines = 2
      };
    

    Hope this helps,

    Greetings, Tobi

    I have followed your solution but I am getting an error and a warning:

    The property 'Lines' was not found in type 'MultiLineLabel'.

    I have of course defined it!

        public class MultiLineLabel : Label
             {
                // Default number of lines is 1 so MultiLineLabel behaves like a standard Label if Lines is not set
                public int Lines = 1;
          }
    

    Also, a warning:

    it says LabelRenderer is obselete and I should use LabelRenderer(context) instead.

  • TobeTobe DEMember ✭✭

    First of all: since Xamarin.Forms 3.30, the Xamarin.Forms.Label has a new property "MaxLines": https://github.com/xamarin/Xamarin.Forms/pull/3318
    Try that, you shouldn't need a Custom Renderer anymore.

    Also, a warning:
    it says LabelRenderer is obselete and I should use LabelRenderer(context) instead.

    Correct, you should write the Constructors for your Labels like this, now:

    public MultiLineLabelRendererDroid(Context context) : base(context)
    {
    }
    

    For more information, have a look at this, that helped me out:
    https://forums.xamarin.com/discussion/106938/context-is-obsolete-as-of-version-2-5

    As of why your Lines property cannot be found, I have no idea, sorry. Need more code to investigate. Maybe you made a mistake with the namespaces or something?
    But as I said, just use the MaxLines property of the Label, and don't use a Custom Renderer at all :-)

  • mac121mac121 Member ✭✭✭
    edited February 28

    @Tobe, great one...!

    The combination of LineBreakMode = "TailTruncation" and MaxLines="(max num of lines)" works very well.. I thought I had to do the limiting of characters by string manipulation in c# before coming across your post!

    E.g. of my label:

    <Label Text="something" LineBreakMode = "TailTruncation" MaxLines = "3" />

    Works exceptionally well both in Android and iOS, no need for custom renderers and additional native tasks to be done

Sign In or Register to comment.