Customized Ellipsis on Label of Xamarin Forms

Cuong 1 Reputation point
2021-09-21T09:52:20.027+00:00

Hello,
As the title says, I want to replace "..." with "...read more" when the label is truncated in Xamarin Forms.
Sorry for my bad english and I hope to get your help.
Thank you very much!

Xamarin
Xamarin
A Microsoft open-source app platform for building Android and iOS apps with .NET and C#.
5,294 questions
0 comments No comments
{count} votes

1 answer

Sort by: Most helpful
  1. Leon Lu (Shanghai Wicresoft Co,.Ltd.) 68,571 Reputation points Microsoft Vendor
    2021-09-22T02:23:30.387+00:00

    Hello,​

    Welcome to our Microsoft Q&A platform!

    Do you want to achieve the result like following screenshot? click the ...Read More show the completely text. then click the read less, make the lable like previous type.

    134173-image.png 134174-image.png

    If so, you can create a custom contentview with two label.

       <?xml version="1.0" encoding="UTF-8"?>  
       <ContentView xmlns="http://xamarin.com/schemas/2014/forms"   
                    xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"  
                    x:Class="App137.CustomLabel">  
         <ContentView.Content>  
                 
                   <StackLayout HorizontalOptions="FillAndExpand" VerticalOptions="FillAndExpand">  
                       <Label x:Name="customLabel"   >  
                       </Label>  
                       <Label x:Name="lblReadMore" FontSize="18" FontAttributes="Bold"  >  
                           <Label.GestureRecognizers>  
                               <TapGestureRecognizer Tapped="TapGestureRecognizer_Tapped" />  
                           </Label.GestureRecognizers>  
                       </Label>  
                   </StackLayout>  
               
           </ContentView.Content>  
       </ContentView>  
    

    Here is contentView's layout background code.

       [XamlCompilation(XamlCompilationOptions.Compile)]  
           public partial class CustomLabel : ContentView  
           {  
               public CustomLabel()  
               {  
                   InitializeComponent();  
               }  
         
               #region Bindable Property  
               public static readonly BindableProperty TextProperty = BindableProperty.Create(  
                   propertyName: nameof(TextProperty),  
                   returnType: typeof(string),  
                   declaringType: typeof(CustomLabel),  
                   defaultBindingMode: BindingMode.TwoWay,  
                   propertyChanged: TextPropertyChanged  
                   );  
         
               public string Text  
               {  
                   get { return (string)base.GetValue(TextProperty); }  
                   set { base.SetValue(TextProperty, value); }  
               }  
         
               //Show the read more label if word length > 100  
               private static void TextPropertyChanged(BindableObject bindable, object oldValue, object newValue)  
               {  
                   var control = (CustomLabel)bindable;  
                   if (newValue != null)  
                   {  
                       control.lblReadMore.IsVisible = false;  
                       control.customLabel.Text = (string)newValue;  
                       var res=control.customLabel.Text.Split().Length;  
                       if (control.customLabel.Text.Split().Length > 30)  
                       {  
                           control.ShortTextVisible = true;  
                           control.ReadMoreLabel = true;  
                       }  
                   }  
               }  
               #endregion  
         
               public bool ReadMoreLabel { get; set; }  
               private bool _shortTextVisible;  
               public bool ShortTextVisible  
               {  
                   get => _shortTextVisible;  
                   set { _shortTextVisible = value; ShortTextPropertyChanged(); }  
               }  
         
               //By Default show first 30 words.  
               private void ShortTextPropertyChanged()  
               {  
                   if (Text != null)  
                   {  
                       if (ShortTextVisible)  
                       {  
                           customLabel.Text = string.Join(" ", Text.Split().Take(30));  
                           lblReadMore.Text = "...Read More";  
                           lblReadMore.IsVisible = true;  
                       }  
                       else  
                       {  
                           customLabel.Text = Text;  
                           lblReadMore.Text = "Read Less";  
                       }  
                   }  
               }  
               private void TapGestureRecognizer_Tapped(object sender, EventArgs e)  
               {  
                   ShortTextVisible = !ShortTextVisible;  
               }  
           }  
    

    You can use it like following code,

       <local:CustomLabel  Text="Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum has been the industry's standard dummy text ever since the 1500s, when an unknown printer took a galley of type and scrambled it to make a type specimen book. It has survived not only five centuries, but also the leap into electronic typesetting, remaining essentially unchanged. It was popularised in the 1960s with the release of Letraset sheets containing Lorem Ipsum passages, and more recently with desktop publishing software like Aldus PageMaker including versions of Lorem Ipsum."    />  
    

    ========================
    Update=========================

    For Android, you can create a custom renderer for your Label. Get if Lable is ellipsized in the OnGlobalLayout method.

    [assembly: ExportRenderer(typeof(Label), typeof(MyLabelRenderer))]
    namespace App137.Droid
    {
    public class MyLabelRenderer: LabelRenderer
    {
    public MyLabelRenderer(Context context) : base(context)
    {

        }  
        protected override void OnElementChanged(ElementChangedEventArgs<Label> e)  
        {  
            base.OnElementChanged(e);  
    
          TextView tv=  Control as TextView;  
            CustomEllipsize(tv,3,"..ReadMore");  
        }  
    
        public void CustomEllipsize( TextView tv,  int maxLine,  String ellipsizetext)  
        {  
    
            if (tv.Tag == null)  
            {  
                tv.Tag=tv.Text;  
            }  
            ViewTreeObserver vto = tv.ViewTreeObserver;  
            vto.AddOnGlobalLayoutListener(new OnGlobalLayoutListener(tv, maxLine, ellipsizetext));   
    

    }
    }

    internal class OnGlobalLayoutListener : Java.Lang.Object, ViewTreeObserver.IOnGlobalLayoutListener  
    {  
        public OnGlobalLayoutListener(TextView tv, int maxLine, string ellipsizetext)  
        {  
            Tv = tv;  
            MaxLine = maxLine;  
            Ellipsizetext = ellipsizetext;  
        }  
    
        public TextView Tv { get; }  
        public int MaxLine { get; }  
        public string Ellipsizetext { get; }  
    
        public void OnGlobalLayout()  
        {  
            //throw new NotImplementedException();  
    
            ViewTreeObserver obs = Tv.ViewTreeObserver;  
            int lineEndIndex111 = Tv.Layout.GetLineEnd(0);  
            obs.RemoveGlobalOnLayoutListener(this);  
    
           Android.Text.Layout  l = Tv.Layout;  
            if (l != null)  
            {  
                int lines = l.LineCount;  
                if (lines > 0)  
                    if (l.GetEllipsisCount(lines - 1) > 0)  
                        Log.Debug("TAG", "Text is ellipsized");  
            }  
    
            if (MaxLine  <= 5)  
            {  
                int lineEndIndex = Tv.Layout.GetLineEnd(0);  
                string text = Tv.Text.Substring(0, lineEndIndex - Ellipsizetext.Length)+ " " + Ellipsizetext;  
                Tv.Text=text;  
            }  
            else if (Tv.LineCount >= MaxLine )  
            {  
                int lineEndIndex = Tv.Layout.GetLineEnd((MaxLine + 1) - 1);  
                string text = Tv.Text.Substring(0, lineEndIndex - Ellipsizetext.Length) + " " + Ellipsizetext;  
                Tv.Text = text;  
            }  
        }  
    }  
         
    

    Best Regards,

    Leon Lu


    If the response is helpful, please click "Accept Answer" and upvote it.

    Note: Please follow the steps in our documentation to enable e-mail notifications if you want to receive the related email notification for this thread.